const auto&
было бы достаточно, если я хочу выполнять операции только для чтения. Тем не менее, я столкнулся с
for (auto&& e : v) // v is non-const
пару раз недавно. Это заставляет меня задуматься:
Возможно ли, что в некоторых неясных угловых случаях есть некоторая выгода в использовании универсальных ссылок по сравнению с auto&
или же const auto&
?
(shared_ptr
подозревается в неясных угловых делах)
Обновить
Два примера, которые я нашел в моих любимых:
Любой недостаток использования константной ссылки при переборе основных типов?
Могу ли я легко перебрать значения карты, используя основанный на диапазоне цикл for?
Пожалуйста, сконцентрируйтесь на вопросе: почему я хочу использовать авто&& на основе диапазона для петель?
Единственное преимущество, которое я вижу, это когда итератор последовательности возвращает ссылку на прокси, и вам нужно работать с этой ссылкой неконстантным способом. Например, рассмотрим:
#include <vector>
int main()
{
std::vector<bool> v(10);
for (auto& e : v)
e = true;
}
Это не компилируется, потому что rvalue vector<bool>::reference
вернулся из iterator
не будет привязываться к неконстантной ссылке на lvalue. Но это будет работать:
#include <vector>
int main()
{
std::vector<bool> v(10);
for (auto&& e : v)
e = true;
}
Несмотря на все сказанное, я бы не стал так кодировать, если бы вы не знали, что нужно удовлетворить такой вариант использования. То есть Я бы не сделал это безвозмездно, потому что это делает заставить людей задуматься о том, что вы делаете. И если бы я это сделал, было бы неплохо добавить комментарий о том, почему:
#include <vector>
int main()
{
std::vector<bool> v(10);
// using auto&& so that I can handle the rvalue reference
// returned for the vector<bool> case
for (auto&& e : v)
e = true;
}
редактировать
Этот мой последний случай действительно должен иметь смысл. Если вы знаете, что цикл всегда обрабатывает ссылку на прокси, то auto
будет работать так же, как auto&&
, Но когда цикл иногда обрабатывает непрокси-ссылки, а иногда и прокси-ссылки, тогда я думаю, auto&&
станет решением выбора.
С помощью auto&&
или же универсальные ссылки с диапазоном for
Преимущество -loop в том, что вы захватываете то, что получаете. Для большинства типов итераторов вы, вероятно, получите T&
или T const&
для какого-то типа T
, Интересный случай, когда разыменование итератора приводит к временному: C ++ 2011 получил смягченные требования, и итераторы не обязательно должны давать lvalue. Использование универсальных ссылок соответствует передаче аргумента в std::for_each()
:
template <typename InIt, typename F>
F std::for_each(InIt it, InIt end, F f) {
for (; it != end; ++it) {
f(*it); // <---------------------- here
}
return f;
}
Функциональный объект f
можно лечить T&
, T const&
, а также T
по-другому. Почему тело на основе диапазона for
петля будет другой? Конечно, чтобы на самом деле воспользоваться выводом типа с использованием универсальных ссылок, вам необходимо передать их соответствующим образом:
for (auto&& x: range) {
f(std::forward<decltype(x)>(x));
}
Конечно, используя std::forward()
означает, что вы принимаете любые возвращаемые значения для перемещения. Имеет ли смысл подобные объекты в не шаблонном коде, я не знаю (пока?). Я могу себе представить, что использование универсальных ссылок может предложить компилятору больше информации для правильного выполнения. В шаблонном коде он не принимает решения о том, что должно происходить с объектами.
Я практически всегда использую auto&&
, Зачем укусить крайний случай, когда вам не нужно? Его тоже короче набирать, и я просто нахожу его более … прозрачным. Когда вы используете auto&& x
тогда вы знаете, что x
это точно *it
, каждый раз.