Почему нельзя использовать auto && для локальных переменных?
В то время как T&&
используется с шаблонами в качестве ссылки пересылки или универсальной ссылки (как их называет Скотт Мейерс), я видел, как некоторые блоги использовали auto&&
в образцах кода. Я думаю, что auto
должно быть достаточно, однако, Herb Sutter в CppCon 2014 говорит: никогда не используйте auto&&
для локальных переменных
Почему это?
Увидев все ответы, я чувствую, что, по-моему, мне следовало спросить об этом. Несмотря на общие правила кодирования, есть ли хорошие варианты использования авто и & внутри тела функции для правильности кода и ремонтопригодности.
Ответы
Ответ 1
Есть случаи, когда вам нужен auto&&
как локальный, подумайте:
vector<bool> vb { true, false, true };
for( auto&& b : vb )
b = !b;
Здесь авто & не сделал бы. (если vector<bool>
является специализированным)
Однако обычная причина, по которой вы используете &&
вместе с выводом типа
(т.е. ссылка на пересылку) заключается в том, что вы не знаете или не заботитесь о
точный тип, вы просто собираетесь отправить его.
Термин "универсальная ссылка" немного вводит в заблуждение, вы не должны использовать
это универсально, отсюда его изменяющееся имя на "ссылку на пересылку"
Обратите внимание, что &&
, не используемый с выводом типа, является ссылкой rvalue, другой
вещь вообще.
Ответ 2
Используя auto && мы просто пропустили контроль над хранилищем переменных. Поэтому мы никогда не должны использовать такой тип дела. старайтесь избегать этого.
Ответ 3
Я соглашусь, что есть один достаточно хороший случай, когда вы хотите использовать цикл range-for для изменения содержимого vector<bool>
. Тем не менее, я бы рекомендовал прочитать "On vector<bool>
" Говарда Хиннанта - человека, ответственного за ссылки rvalue.
Помимо этой аберрации, нет мотивационного примера, чтобы показать использование auto&&
для локальных переменных. Каждое использование локальной переменной auto&&
является злоупотреблением (что на самом деле означает Sutter), за исключением общих лямбда. Мотивируя, я имею в виду, что вы не можете написать оптимальный и правильный код (без имплицитных преобразований и т.д.) Без auto&&
. Вы можете использовать его только потому, что вы ждали, чтобы использовать ядерное оружие, чтобы убить мышь. Давайте рассмотрим некоторые случаи, которые, возможно, кажутся актуальными.
-
Оператор , основанный на диапазоне, определен в п. 6.5.4, чтобы быть эквивалентным:
{
auto && __range = range-init;
for ( auto __begin = begin-expr, __end = end-expr;
__begin != __end; ++__begin )
{
for-range-declaration = *__begin;
statement
}
}
Теперь это чисто теоретическое. Давайте сделаем мысленный эксперимент и скажем, что компилятор делает это. Компиляторы не известны для реализации на высоком уровне. Даже если они это делают, вы уверены, что можете получить одно выражение range-init
, чтобы управлять ими всеми.
-
Мой собственный аргумент пересылки пересылаемой ссылки через несколько интерфейсов. Если вы просто хотите переслать, зачем вам нужно auto&&
с именем alias. Просто вперед.
-
Что делать, если функция возвращает универсальную ссылку. В самом деле?? Перегрузка по типу возврата запрещена. Вы можете сделать это через шаблоны. Однако в связанном вопросе пример передает T
в качестве аргумента шаблона, а также возвращает T
. Если вы говорите, что T
может быть значением rvalue или lvalue, и я хочу использовать auto&&
, у вас есть амнезия.
-
Продолжая 3, даже если вы гипотетически не знаете, получаете ли вы T
или T&
из черного ящика (я бы избегал такого поля), вы не можете получить ничего значимого, не вызывая, lvalue или rvalue. Если вы хотите переслать только вперед.
-
Проблема цикла для цикла. Позвольте мне обобщить это. Рассмотрим общий пример использования, например for( auto x : {a, b , c})
или for(auto x : getVector())
или подобные случаи. Вы хотите использовать for(auto&& b : vb)
, потому что vb
может быть временным, и вы также можете изменить содержимое временного. В моей конечной мудрости я не понимаю, почему вы хотите изменить содержимое временного вектора или списка. Вы можете продолжать использовать аргументы, например, следующий элемент может зависеть от измененного предыдущего значения и т.д., Но вы можете найти оптимальное решение без auto&&
. Лично я считаю, что изменение временного содержимого без привязки к const T&
должно быть объявлено вне закона.
-
Аргумент Variadic template. Мне приснилось, что если мне нужно очистить первый аргумент от var...
, я могу использовать auto&&
или T&&
. Я не думаю, что даже это держит воду. Посоветуйте мне, если может быть правдоподобный случай.
-
Я хочу, чтобы auto&&
связал что-то. Затем используйте его для цикла. Просто используйте его внутри цикла.
-
Аргумент killer, если вы действительно создаете достаточно хороший случай, кроме lambdas: Вы не можете писать достаточно строк, не определяя или не фиксируя его как T
или T&
. В противном случае, потому что вы хотите написать оптимальный код, у вас будет раздутый код... для каждой строки, которую вы пишете, вам нужно будет проверить, делает ли rvalue еще что-либо, если rvalue делает это. Лучше использовать свойства типа в начале, чтобы определить r/l-ценность.
Пожалуйста, добавьте новые примеры или хорошие варианты использования, если вы столкнетесь с ними.