decltype na zmiennej typu referencyjnego z nawiasami klamrowymi

Dec 15 2020

Rozważ następujący kod :

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

Typ v1jest wywnioskowany jako int. Jednocześnie v2oczekuje się, że typ const int&. Myślę, że pierwszy krok v1można potraktować jako dodanie jeszcze jednego aliasu typu, using T = decltype(p);a następnie auto v4 = T{};. Jak to wyrażenie ( decltype(p){}lub T{}) jest traktowane przez kompilator? Wiem, że ta {}część jest przeznaczona do tworzenia instancji, ale w jaki sposób wynikowy typ v1nie jest typem referencyjnym?

Jeszcze inne pytanie: czy istnieje sposób na zadeklarowanie v3zmiennej tego samego typu, co v1przy użyciu jawnie wskazanego typu const int&(zamiast decltype(p))?

Wszelkie linki do standardu będą mile widziane.

Odpowiedzi

1 Enlico Dec 15 2020 at 00:48

(Do przeciwników: jeśli zgodzisz się, ponieważ uważasz, że cytowanie Scotta Meyersa nie jest równoznaczne z cytowaniem normy, no cóż ...)

Jak możesz przeczytać w Effective Modern C ++ (wzbogaconym o część erraty , do której można dotrzeć, wyszukując Case 2:ten link, a to tylko upraszcza czytanie, ale nie jest to niezbędne do pytania):

Jeśli nie ParamTypejest odniesieniem [...] jeśli exprtyp jest odniesieniem, zignoruj ​​część odniesienia. Jeśli [...] exprjest const, to też zrób to. Jeśli tak volatile, zignoruj ​​to.

gdzie paramjest specyfikatorem deklaracji, co w twoim przypadku jest po prostu auto, tj. bez odniesienia.

Innymi słowy, tworzysz v1przez zwykły auto(nie auto&), tj. Przez kopiowanie, więc nie ma znaczenia, czy inicjujesz go z bytem, ​​który jest odniesieniem, czy nie, czy nawet z constlub nie ( volatilelub nie, fwiw), ponieważ to kopiujesz.

Pomyśl o prostszym przypadku,

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

jeśli chodzi o v1to, to naprawdę nie jest ważne, czy jest inicjowane jedną ( i), czy drugą ( p) nazwą, pod którą znana jest ta sama jednostka, ponieważ otrzyma kopię dowolnej wartości, jaką ma ta jednostka.

autodedukcja typów działa tak samo jak dedukcja typów szablonów (z wyjątkiem różnicy w sposobie, w jaki radzą sobie z inicjalizatorem ze wzmocnieniem, co nie jest istotne w tym przypadku) i dla obu z nich możesz odwołać się do Efektywnego nowoczesnego C ++ Scotta Meyersa .