c++ c++11 c++14 universal-reference forwarding-reference

c++ - ¿Cuál es el nombre estándar/oficial para referencias universales?



c++11 c++14 (1)

Sé que si se declara que una variable o parámetro tiene el tipo T&& para un tipo deducido T , esa variable o parámetro se denomina referencia universal .

El término referencia universal fue introducido por Scott Meyers en su discurso original "Referencias universales en C ++ 11" . Sin embargo, me pregunto cuál es el término oficial / estándar para referencias universales .


Visión general

Se sabe que desde C ++ 11, un parámetro de tipo T&& se llama referencia de valor [ ISO / IEC 14882: 2011 §8.3.2 / p2 Referencias [dcl.ref] ]. Es decir, a menos que T sea ​​un tipo de parámetro de plantilla o auto o un typedef para algún tipo de referencia de valor.

ejemplos:

template<typename T> void foo(T&& p) { // -> T is a template parameter ... } auto &&p = expression;

Aunque técnicamente T&& en los ejemplos anteriores sigue siendo una referencia de valor, su comportamiento difiere significativamente de uno normal.

Naturalmente, usted preguntaría "por qué este caso especial no tiene una sintaxis especial". La respuesta es que la sintaxis de && fue sobrecargada intencionalmente para esta construcción especial por el comité de C ++. Sin embargo, fallaron en nombrar este caso especial.

En ausencia de un nombre distinto para esta construcción en particular, Scott Meyers acuñó las referencias universales de término / nombre ampliamente conocidas.

Sin embargo, el comité decidió que este nombre no es apropiado por varias razones. Como tal, la propuesta N4164 hecha por Herb Sutter , Bjarne Stroustrup y Gabriel Dos Reis propuso cambiar el nombre a Referencias de reenvío .

El nombre Reenvío de Referencias tuvo el mayor apoyo en las discusiones informales entre los miembros del comité, incluidos los autores de la propuesta mencionada anteriormente. Curiosamente, fue el mismo Scott Meyers quien introdujo ese término en su charla original sobre "Referencias universales". Sin embargo, más tarde decidió seguir el nombre de referencias universales . Para esta decisión fue importante el hecho de que en ese momento no pensaba que el término de reenvío de referencias incluyera también el caso de auto&& .

¿Por qué no referencias universales ?

Según la propuesta, el término referencias universales, aunque es un nombre razonable con un significado obvio, resulta incorrecto en varios aspectos.

Una referencia universal debe significar lo siguiente:

  • Una referencia que se puede utilizar en todas partes; o
  • Una referencia que se puede utilizar para todo; o
  • algo parecido.

Obviamente, este no es el caso ni es el uso apropiado de este constructo. Además, este nombre alentaría a muchas personas a considerar que algo que tenga ese nombre debe utilizarse "universalmente". Algo que el comité consideró como algo malo.

Además, las "referencias universales" ni siquiera son realmente referencias per se, sino más bien un conjunto de reglas para usar las referencias de una manera particular en un contexto particular con algún soporte de lenguaje para ese uso, y ese uso es reenviar .

¿Por qué auto&& también se considera un caso de reenvío?

auto&& también se considera un caso hacia adelante ya que sigue las reglas de colapso de referencia . Por ejemplo en:

  • Las lambdas genéricas de la forma, [](auto&& x){ … }
  • for bucle de la forma, for(auto &&i : v) { ... }
  • Finalmente, en general es cierto que las variables auto&& locales son para reenvío.

Palabras estándar para reenviar referencias

El término referencias de reenvío se menciona en el proyecto de norma N4527 en los siguientes lugares:

§14.8.2.1 / Deducir argumentos de plantilla de una llamada de función [temp.deduct.call] (énfasis en la mina) :

Si P es un tipo calificado de CV, los calificadores de CV de nivel superior del tipo P se ignoran para la deducción de tipo. Si P es un tipo de referencia, el tipo referido por P se usa para la deducción de tipo. Una referencia de reenvío es una referencia rvalue a un parámetro de plantilla no calificada cv. Si P es una referencia de reenvío y el argumento es un lvalor, se usa el tipo "lvalue reference to A" en lugar de A para la deducción de tipo. [Ejemplo:

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

- ejemplo final]

§14.8.2.5 / p10 Deducir argumentos de plantilla de un tipo [temp.deduct.type]:

De manera similar, si P tiene una forma que contiene (T), cada tipo de parámetro Pi de la lista de tipos de parámetros respectiva de P se compara con el tipo de parámetro correspondiente Ai de la lista de tipo de parámetro correspondiente de A. Si P y A son los tipos de función que se originaron a partir de la deducción al tomar la dirección de una plantilla de función (14.8.2.2) o al deducir los argumentos de plantilla de una declaración de función (14.8.2.6) y Pi y Ai son parámetros de la lista de tipos de parámetros de nivel superior de P y A, respectivamente, Pi se ajusta si es una referencia de reenvío (14.8.2.1) y Ai es una referencia de valor, en cuyo caso el tipo de Pi se cambia para que sea el tipo de parámetro de la plantilla (es decir, T&& se cambia a simplemente T). [Nota: Como resultado, cuando Pi es T&& y Ai es X& , la Pi ajustada será T, lo que hará que T se deduzca como X& . - nota final] [Ejemplo:

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 }

- ejemplo final] Si la declaración de parámetros correspondiente a Pi es un paquete de parámetros de función, entonces el tipo de su declaratorid se compara con cada tipo de parámetro restante en la lista de parámetros de tipo A. Cada comparación deduce los argumentos de la plantilla para las posiciones subsiguientes en los paquetes de parámetros de plantilla expandidos por el paquete de parámetros de función. Durante el pedido parcial (14.8.2.4), si Ai era originalmente un paquete de parámetros de función: