decltype na variável do tipo de referência com chaves

Dec 15 2020

Considere o seguinte 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 {};
}

O tipo de v1é deduzido como int. Ao mesmo tempo, o tipo de v2é esperado como const int&. Acho que o primeiro passo para v1poderia ser tratado como adicionar mais um alias de tipo using T = decltype(p);e então auto v4 = T{};. Como esta expressão ( decltype(p){}ou T{}) é tratada pelo compilador? Eu sei que essa {}parte é para instanciação, mas como o tipo resultante de v1não é um tipo de referência?

Ainda outra pergunta: há uma maneira de declarar v3variável do mesmo tipo que v1usar tipo explicitamente anotado const int&(em vez de decltype(p))?

Quaisquer links para o padrão serão apreciados.

Respostas

1 Enlico Dec 15 2020 at 00:48

(Para o (s) downvoter (es): se você votou contra porque acha que citar Scott Meyers não é equivalente a citar o padrão, tudo bem ...)

Como você pode ler em Effective Modern C ++ (ampliado com a parte da errata que você pode alcançar pesquisando Case 2:nesse link, e isso apenas torna a leitura a seguir mais simples, mas não é essencial para a questão):

Se não ParamTypefor uma referência [...] se expro tipo for uma referência, ignore a parte da referência. Se exprfor const, ingore isso também. Se for volatile, ignore também.

onde paramestá o especificador de declaração, que no seu caso é justo auto, ou seja, uma não referência.

Em outras palavras, você está criando v1via simples auto(não auto&), ou seja, por cópia, então não importa se você está inicializando com uma entidade que é referência ou não, ou mesmo com constou não ( volatileou não, fwiw), porque você está copiando.

Pense no caso mais simples,

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

no que diz v1respeito a isso, realmente não é importante se ele é inicializado com um ( i) ou outro ( p) nome pelo qual a mesma entidade é conhecida, porque ela obterá uma cópia de qualquer valor que essa entidade tenha.

autoa dedução de tipo funciona da mesma forma que a dedução de tipo de modelo (exceto por uma diferença em como eles lidam com o inicializador com chaves, que não é relevante neste caso), e para ambos você pode consultar o Effective Modern C ++ de Scott Meyers .