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

Что такое "кратковременная система для петель"?

clang начал внедрять краткие ранговые настройки для циклов из n3994. Часто при внедрении циклов, основанных на диапазонах, мы видим код в форме for (auto & v : vector), чтобы избежать ненужного копирования. Кажется, что n3994 предлагает, чтобы for (auto && v : vector) превосходил всех. У меня есть несколько вопросов:

  • Какие преимущества дает последняя форма над первым? Почему мы обычно ходим с auto & вместо auto &&, если последнее явно выгодно?
  • Заставляет ли новый цикл, основанный на диапазонах, равным auto && сломать существующий код? Это повлияет на новый код?
  • Разве это не означало бы, что их код на самом деле эквивалентен auto &&?
4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

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

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

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

Ответ 2

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

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

Является ли создание нового цикла, основанного на диапазоне, эквивалентным авто и & собирается ли нарушить существующий код? Это повлияет на новый код?

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

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

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