Что является «кратко-основанным для петель»?

Clang начал реализацию кратко-на основе для петель от n3994. Часто при представлении циклических для циклов мы видим код в виде for (auto & v : vector) чтобы избежать ненужного копирования. Похоже, что N3994 предлагает for (auto && v : vector) превосходит во всех отношениях. У меня есть несколько вопросов:

  1. Какие преимущества предлагает последняя форма по сравнению с первой? Почему мы обычно идем с auto & вместо auto && если последнее явно выгодно?
  2. Делает новый цикл на основе диапазона эквивалентным auto && собирается сломать существующий код? Будет ли это реально влиять на новый код?
  3. Разве это не вводит в заблуждение начинающих, что их код на самом деле эквивалентен auto &&?

19

Решение

Какие преимущества предлагает последняя форма по сравнению с первой?

В виде for(auto& v : vector), тип v выводится как lvalue ссылка на тип, полученный разыменованием типа итератора контейнера. Это означает, что если результат разыменования итератор является rvalue (думаю, std::vector<bool> который возвращает тип прокси, представляющий ссылку на один bool значение), то код не будет скомпилирован, потому что ссылка lvalue не может привязаться к rvalue.

Когда ты пишешь for(auto&& v : vector), это универсальная ссылка, имея в виду тип v либо будет выведен как ссылка на значение в случае, описанном выше; или в качестве ссылки lvalue в обычном случае, когда разыменование итератора возвращает ссылку на элемент контейнера. Так что работает в vector<bool> дело также. Вот почему эта форма должна быть предпочтительной, если вы планируете модифицировать элементы, которые вы повторяете в цикле.

Почему мы обычно идем с auto& вместо auto&& если последнее явно выгодно?

Ты не должен. Единственный недостаток, о котором я могу думать auto&& в том, что это не гарантирует, что изменения, которые вы вносите в элементы, обязательно распространятся обратно в контейнер, но это свидетельствует о нарушении дизайна, и я не думаю, что от него стоит защищаться.

Делает новый цикл на основе диапазона эквивалентным auto && собирается сломать существующий код?

Я не понимаю, как он может сломать существующий код, потому что старый синтаксис продолжит функционировать, как сегодня. Но если вы имеете в виду замену существующего кода новым синтаксисом, то это может иметь эффект, если заменяемый код будет auto const& форма. Увидеть этот пример. Обратите внимание, как auto const& версия называет const функция-член, в то время как другие два вызываютconst версия? Замена первого краткой версией изменит вызываемую функцию-член.

Будет ли это реально влиять на новый код?

Опять же, это не отличается от старого кода, который использует auto&& сегодня, так что это не увидит никакой разницы. Если вы используете его в местах, где вы не собираетесь изменять элементы, то компилятор больше не будет мешать вам сделать это случайно, и вы можете вызвать другую перегрузку, как показано в примере выше.

Разве это не вводит в заблуждение начинающих, что их код на самом деле эквивалентен auto &&?

Я не уверен, что понимаю, что вы подразумеваете под этим, но если вы спрашиваете, будут ли новички писать код, не зная или не понимая тонкостей свертывания ссылок, то да, возможно, они это сделают. Но это одна из заявленных целей статьи, с которой вы связаны. Аргумент заключается в том, что вы можете избежать обучения этим сложным концепциям сразу, но познакомить новичков с единым синтаксисом для диапазона. for петли, которые работают со всем. Что касается этого, я думаю, что синтаксис имеет свои достоинства, но, глядя на это с const Правильность перспективы, я нахмурился, потому что я бы предпочел использовать auto const& если я хочу доступ только для чтения к элементам, а затем краткий синтаксис кажется асимметричным.

10

Другие решения

Какие преимущества предлагает последняя форма по сравнению с первой? Почему мы обычно идем с auto & вместо auto && если последний
явно выгодно?

auto & не работает, если разыменование итератора возвращает прокси-объекты, а не фактические ссылки, поскольку вы пытаетесь связать неконстантную ссылку lvalue с временной. Стандартным примером является мерзость, известная как std::vector<bool>; разыменование его итератора возвращает прокси-объект типа std::vector<bool>::reference который представляет один бит в векторе. Поскольку большинство итераторов возвращают реальные ссылки, вы не часто сталкиваетесь с этой проблемой.

Делает новый цикл на основе диапазона эквивалентным авто && собирается сломать существующий код? Будет ли это реально влиять на новый код?

Нет, потому что новый синтаксис, for(elem : range), не скомпилируется в существующем коде.

Разве это не вводит в заблуждение начинающих, что их код на самом деле эквивалентен auto &&?

Почему это будет гоча? auto && имеет то преимущество, что оно действительно работает для всего. Кто-то может возразить, что отсутствие необходимости обучать новичков всем деталям, связанным с выводом типов, свертыванием ссылок и т. Д., На самом деле является плюсом, поскольку облегчает изучение языка.

8