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';
}
Здравствуйте, 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.
Здравствуйте, 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)