decltype sur la variable de type référence avec accolades

Dec 15 2020

Considérez le code suivant :

#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 {};
}

Le type de v1est déduit comme int. Dans le même temps, le type de v2est normalement déduit comme const int&. Je pense que la première étape pour v1pourrait être traitée comme l'ajout d'un autre alias de type using T = decltype(p);, puis auto v4 = T{};. Comment cette expression ( decltype(p){}ou T{}) est-elle traitée par le compilateur? Je sais que cette {}partie est destinée à l'instanciation, mais comment le type résultant de v1n'est pas un type de référence?

Encore une autre question: existe-t-il un moyen de déclarer une v3variable du même type en v1utilisant un type explicitement noté const int&(au lieu de decltype(p))?

Tout lien vers la norme serait apprécié.

Réponses

1 Enlico Dec 15 2020 at 00:48

(Aux votants négatifs: si vous avez voté contre parce que vous pensez que citer Scott Meyers n'équivaut pas à citer la norme, eh bien ...)

Comme vous pouvez le lire à partir de Effective Modern C ++ (augmenté de la partie de l' errata que vous pouvez atteindre en recherchant Case 2:sur ce lien, et cela simplifie simplement la lecture suivante, mais ce n'est pas essentiel à la question):

Si ParamTypeest une non-référence [...] si exprle type est une référence, ignorez la pièce de référence. Si [...] exprc'est le cas const, pensez-y aussi. Si c'est le cas volatile, ignorez-le également.

paramest le spécificateur de déclaration, qui dans votre cas est juste auto, c'est-à-dire une non-référence.

En d'autres termes, vous créez v1via plain auto(non auto&), c'est-à-dire par copie, donc peu importe que vous l'initialisiez avec une entité qui est référence ou non, ou même avec constou pas ( volatileou pas, fwiw), parce que vous le copiez.

Pensez au cas le plus simple,

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

en ce qui le v1concerne, ce n'est vraiment pas important qu'il soit initialisé avec l'un ( i) ou l'autre ( p) nom sous lequel la même entité est connue, car elle obtiendra une copie de la valeur de cette entité.

autoLa déduction de type fonctionne comme la déduction de type de modèle (sauf pour une différence dans la façon dont ils traitent l'initialiseur renforcé, ce qui n'est pas pertinent dans ce cas), et pour les deux, vous pouvez vous référer au C ++ moderne efficace de Scott Meyers .