Подтвердить что ты не робот

Почему нельзя использовать auto && для локальных переменных?

В то время как T&& используется с шаблонами в качестве ссылки пересылки или универсальной ссылки (как их называет Скотт Мейерс), я видел, как некоторые блоги использовали auto&& в образцах кода. Я думаю, что auto должно быть достаточно, однако, Herb Sutter в CppCon 2014 говорит: никогда не используйте auto&& для локальных переменных

Почему это?

Увидев все ответы, я чувствую, что, по-моему, мне следовало спросить об этом. Несмотря на общие правила кодирования, есть ли хорошие варианты использования авто и & внутри тела функции для правильности кода и ремонтопригодности.

4b9b3361

Ответ 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-ценность.

Пожалуйста, добавьте новые примеры или хорошие варианты использования, если вы столкнетесь с ними.