Какое стандартное / официальное название для универсальных ссылок?

Я знаю, что если переменная или параметр объявлен, чтобы иметь тип 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 изначально был пакетом параметров функции:

Другие вопросы по тегам