Какое стандартное / официальное название для универсальных ссылок?
Я знаю, что если переменная или параметр объявлен, чтобы иметь тип T&&
для какого-то выведенного типа T
Эта переменная или параметр широко называется универсальной ссылкой.
Термин универсальная ссылка был введен Скоттом Мейерсом в его оригинальном выступлении "Универсальные ссылки в C++11". Однако мне интересно, каков официальный / стандартный термин для универсальных ссылок.
1 ответ
обзор
Известно, что начиная с C++11, параметр типа T&&
называется эталонной ссылкой [ ISO / IEC 14882: 2011 §8.3.2 / p2 References [dcl.ref] ]. То есть, если T
это тип параметра шаблона или auto
или typedef
для некоторого lvalue ссылочного типа.
Примеры:
template<typename T> void foo(T&& p) { // -> T is a template parameter ... } auto &&p = expression;
Хотя технически T&&
в приведенных выше примерах это ссылка на значение, ее поведение значительно отличается от обычного.
Естественно, вы спросите: "почему этот особый случай не имеет специального синтаксиса". Ответ в том, что &&
Синтаксис был преднамеренно перегружен для этой специальной конструкции комитетом C++. Однако они упустили возможность назвать этот особый случай.
В отсутствие четкого названия для этой конкретной конструкции Скотт Мейерс придумал широко известный термин / имя универсальные ссылки.
Комитет, однако, решил, что это имя не подходит по ряду причин. Таким образом, предложение N4164, внесенное Хербом Саттером, Бьярном Страуструпом и Габриэлем Дос Рейсом, предложило изменить название на Переадресация ссылок.
Название Forwarding References получило наибольшую поддержку в неофициальных дискуссиях между членами комитета, включая авторов предложения, упомянутого ранее. Интересно, что сам Скотт Мейерс ввел этот термин в свое первоначальное выступление "Универсальные ссылки". Однако позже он решил согласиться с именем универсальной ссылки. Для этого решения сыграл роль тот факт, что в то время он не думал, что термин пересылка ссылок включает также auto&&
дело.
Почему не универсальные ссылки?
Согласно предложению термин универсальные ссылки хотя и является разумным названием с очевидным значением, в некоторых аспектах он ошибочен.
Универсальная ссылка должна означать следующее:
- Ссылка, которая может использоваться везде; или же
- Ссылка, которая может быть использована для всего; или же
- что-то похожее.
Очевидно, что это не так, и не является надлежащим использованием этой конструкции. Кроме того, это имя побудило бы многих людей задуматься о том, что нечто, имеющее такое имя, предназначено для "универсального использования". То, что комитет посчитал это плохой вещью.
Более того, "универсальные ссылки" на самом деле даже не являются ссылками сами по себе, а представляют собой набор правил для использования ссылок определенным образом в определенном контексте с некоторой языковой поддержкой для этого использования, и это использование - пересылка.
Зачем auto&&
Также рассматривается случай пересылки
auto&&
также считается форвардным случаем, поскольку он следует правилам свертывания ссылок. Например в:
- Общие лямбды формы,
[](auto&& x){ … }
for
петля формы,for(auto &&i : v) { ... }
- Наконец, в целом верно то, что
auto&&
локальные переменные предназначены для пересылки.
Стандартные формулировки для пересылки ссылок
Термин пересылка ссылок упоминается в проекте стандарта N4527 в следующих местах:
§14.8.2.1 / Вывод аргументов шаблона из вызова функции [temp.deduct.call] (Акцент Mine):
Если P является cv-квалифицированным типом, cv-квалификаторы верхнего уровня типа P игнорируются для вывода типа. Если P является ссылочным типом, тип, на который ссылается P, используется для вывода типа. Ссылка для пересылки - это rvalue-ссылка на неквалифицированный cv параметр шаблона. Если P является ссылкой для пересылки, а аргумент является lvalue, тип "lvalue ссылка на A" используется вместо A для вывода типа. [ Пример:
template <class T> int f(T&& heisenreference); template <class T> int g(const T&&); int i; int n1 = f(i); // calls f<int&>(int&) int n2 = f(0); // calls f<int>(int&&) int n3 = g(i); // error: would call g<int>(const int&&), which // would bind an rvalue reference to an lvalue
- конец примера]
§14.8.2.5 / p10 Вывод аргументов шаблона из типа [temp.deduct.type]:
Аналогично, если P имеет форму, которая содержит (T), то каждый тип параметра P i соответствующего списка типов параметров P сравнивается с соответствующим типом параметра Ai соответствующего списка параметров типа A. Если P и A являются Типы функций, которые возникли из дедукции при получении адреса шаблона функции (14.8.2.2) или при выводе аргументов шаблона из объявления функции (14.8.2.6), а P i и Ai являются параметрами списка параметров типа верхнего уровня P и A соответственно, Pi корректируется, если это ссылка на пересылку (14.8.2.1), а Ai является ссылкой lvalue, и в этом случае тип P i изменяется на тип параметра шаблона (т. Е. T&& изменяется на просто Т). [Примечание: в результате, когда P i
T&&
и АйX&
, скорректированный P i будет T, в результате чего T будет выведен какX&
, - примечание конца] [Пример:template <class T> void f(T&&); template <> void f(int&) { } // #1 template <> void f(int&&) { } // #2 void g(int i) { f(i); // calls f<int&>(int&), i.e., #1 f(0); // calls f<int>(int&&), i.e., #2 }
- конец примера] Если объявление параметра, соответствующее P i, является пакетом параметров функции, то тип его объявления ID сравнивается с каждым оставшимся типом параметра в списке типов параметров А. Каждое сравнение выводит аргументы шаблона для последующих позиций в пакеты параметров шаблона, расширенные пакетом параметров функции. Во время частичного упорядочения (14.8.2.4), если Ai изначально был пакетом параметров функции: