decltype en la variable de tipo de referencia con llaves

Dec 15 2020

Considere el siguiente código :

#include <type_traits>

int main() {
    const int& p = 42;
    auto v1 = decltype(p){};
    static_assert(std::is_same_v<decltype(v1), int>);
    
    decltype(p) v2{};
    static_assert(std::is_same_v<decltype(v2), const int&>);
    // auto v3 = X(const int&)X {};
}

El tipo de v1se deduce como int. Al mismo tiempo, v2se espera que el tipo de const int&. Creo que el primer paso para v1podría tratarse como agregar un alias de tipo más using T = decltype(p);y luego auto v4 = T{};. ¿Cómo trata el compilador esta expresión ( decltype(p){}o T{})? Sé que esa {}parte es para la creación de instancias, pero ¿cómo el tipo resultante de v1no es un tipo de referencia?

Otra pregunta más: ¿hay alguna manera de declarar una v3variable del mismo tipo que si se v1usa un tipo anotado explícitamente const int&(en lugar de decltype(p))?

Se agradecería cualquier enlace al estándar.

Respuestas

1 Enlico Dec 15 2020 at 00:48

(Para los votantes en contra: si votó en contra porque cree que citar a Scott Meyers no es equivalente a citar el estándar, bueno ...)

Como puede leer de Effective Modern C ++ (aumentado con la parte de la errata a la que puede llegar buscando Case 2:en ese enlace, y eso solo hace que la siguiente lectura sea más simple, pero no es esencial para la pregunta):

Si no ParamTypees una referencia [...] si exprel tipo es una referencia, ignore la parte de referencia. Si [...] expres const, Ingore eso también. Si es así volatile, ignóralo también.

donde parames el especificador de declaración, que en su caso es solo auto, es decir, una no referencia.

En otras palabras, está creando a v1través de simple auto(no auto&), es decir, por copia, por lo que no importa si lo está inicializando con una entidad que es referencia o no, o incluso con consto no ( volatileo no, fwiw), porque lo estás copiando.

Piense en el caso más simple,

int i = 3;
int& p = i;
auto v1 = p;

en lo que v1respecta, realmente no es importante si se inicializa con uno ( i) u otro ( p) nombre por el que se conoce la misma entidad, porque obtendrá una copia de cualquier valor que tenga esa entidad.

autola deducción de tipo funciona igual que la deducción de tipo de plantilla (excepto por una diferencia en cómo tratan con el inicializador arriostrado, que no es relevante en este caso), y para ambos puede consultar el C ++ efectivo moderno de Scott Meyers .