C++11/14 idioms I use every day
От: flаt  
Дата: 19.08.14 11:49
Оценка:
http://seshbot.com/blog/2014/08/16/modern-c-plus-plus-idioms-i-use-every-day/

Возник вопрос по

the proposal for enhanced ranged-based for syntax to prevent accidental misuse (currently the recommended syntax is actuall for (auto && x : xs), but this will allow us to use for (x : xs))


Почему (точнее, для чего) в range-based for нужна RV-ссылка, а не обычная? В каких случаях это может потребоваться?

ЗЫ: https://github.com/ryanhaining/cppitertools/ — классная штука:

for (auto i : range(10)) {
    cout << i << '\n';
}
vector<int> vec{2, 4, 6, 8};
for (auto e : enumerate(vec)) { 
    cout << e.index
         << ": "
         << e.element
         << '\n';
}
Re: C++11/14 idioms I use every day
От: Constructor  
Дата: 19.08.14 14:56
Оценка: 105 (7)
Здравствуйте, flаt, Вы писали:

F>Почему (точнее, для чего) в range-based for нужна RV-ссылка, а не обычная?


Во-первых, auto&& — это не rvalue-ссылка, а один из двух способов получить т.н. универсальную ссылку в C++11+.
Во-вторых, operator* итератора контейнера может возвращать не только lvalue-ссылку на соответствующий элемент контейнера. Поэтому следующий код

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v(5);
    
    for (auto& e : v)
    {
        e = 1;
    }
    for (auto e : v)
    {
        std::cout << e << " ";
    }
}

работает, а этот — уже нет (не компилируется):

#include <iostream>
#include <vector>

int main()
{
    std::vector<bool> v(5);
    
    for (auto& e : v)
    {
        e = true;
    }
    std::cout << std::boolalpha;
    for (auto e : v)
    {
        std::cout << e << " ";
    }
}

Работать в данном случае, как ни странно, будет код без ссылкиauto вместо auto&).
А все потому, что методы std::vector<bool> и его итераторов при прямом доступе к элементам контейнера возвращают не bool&/const bool&, а std::vector<bool>::reference.

F>В каких случаях это может потребоваться?


Когда Вы точно знаете, с каким контейнером Вы работаете, универсальная ссылка не нужна, Вы сами можете выбрать, что именно следует писать (auto&/const auto& или просто auto). Но если Вы задумали писать шаблонный код, то без универсальной ссылки постоянно придется писать лишние специализации. А с ней все очень просто:

#include <iostream>
#include <vector>

template <typename T>
void Assign(std::vector<T>& v, T a)
{
    for (auto&& e : v)
    {
        e = a;
    }
}

template <typename T>
void Print(const std::vector<T>& v)
{
    for (const auto& e : v)
    {
        std::cout << e << " ";
    }
}

int main()
{
    std::vector<int> vi(5);
    std::vector<bool> vb(5);
    
    Assign(vi, 1);
    Assign(vb, true);
    Print(vi);
    std::cout << std::boolalpha << std::endl;
    Print(vb);
}

См. также аналогичный вопрос на StackOverflow.
Отредактировано 27.03.2017 13:54 Constructor . Предыдущая версия .
Re: C++11/14 idioms I use every day
От: Кодт Россия  
Дата: 25.08.14 09:19
Оценка: :)
Здравствуйте, flаt, Вы писали:

F>

the proposal for enhanced ranged-based for syntax to prevent accidental misuse (currently the recommended syntax is actuall for (auto && x : xs), but this will allow us to use for (x : xs))


Оффтопик. Смотрю на этот код и думаю, какого чёрта, сделали паттерн-матчинг конструктора списков в стиле хаскелла:
map f [] = []
map f (x : xs) = (f x) : (map f xs)

Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.