Temat był wcześniej omawiany , ale to nie jest duplikat.
Kiedy ktoś pyta o różnicę między decltype(a)
i decltype((a))
, jak zwykle odpowiedź brzmi - a
jest to zmienna, (a)
jest wyrazem. Uważam tę odpowiedź za niezadowalającą.
Po pierwsze, a
jest to także wyrażenie. Opcje wyrażenia podstawowego obejmują między innymi:
- ( wyrażenie )
- wyrażenie id
Co ważniejsze, frazowanie dla dekltype uwzględnia nawiasy bardzo, bardzo wyraźnie :
For an expression e, the type denoted by decltype(e) is defined as follows:
(1.1) if e is an unparenthesized id-expression naming a structured binding, ...
(1.2) otherwise, if e is an unparenthesized id-expression naming a non-type template-parameter, ...
(1.3) otherwise, if e is an unparenthesized id-expression or an unparenthesized class member access, ...
(1.4) otherwise, ...
Pozostaje więc pytanie. Dlaczego nawiasy są traktowane inaczej? Czy ktoś jest zaznajomiony z dokumentami technicznymi lub dyskusjami komitetów? Bezpośrednie rozważenie nawiasów prowadzi do przekonania, że nie jest to niedopatrzenie, więc musi istnieć techniczny powód, dla którego tęsknię.
c++
c++11
language-lawyer
decltype
Ofek Shilon
źródło
źródło
(a)
jest wyrażeniem ia
jest wyrażeniem i zmienną”.Odpowiedzi:
To nie jest niedopatrzenie. Interesujące jest to, że w Decltype i auto (wersja 4) (N1705 = 04-0145) znajduje się oświadczenie:
Ale w Decltype (wersja 6): proponowane sformułowanie (N2115 = 06-018) jedną ze zmian jest
Nie ma żadnego uzasadnienia w sformułowaniu, ale przypuszczam, że jest to rodzaj rozszerzenia dekltypy przy użyciu nieco innej składni, innymi słowy, zamierzano rozróżnić te przypadki.
Użycie do tego pokazane jest w C ++ draft9.2.8.4:
Co jest naprawdę interesujące, to jak działa ze
return
stwierdzeniem:Moje Visual Studio 2019 sugeruje, żebym usunął zbędny nawias, ale w rzeczywistości zmieniają się, w
decltype((i))
które zmiany zwracają wartość,int&
co powoduje, że jest to UB, ponieważ zwraca odwołanie do zmiennej lokalnej.źródło
Nawiasy nie są traktowane inaczej. To niepozorowane wyrażenie id jest traktowane inaczej.
Gdy nawiasy są obecne, obowiązują regularne reguły dla wszystkich wyrażeń. Typ i kategoria wartości są wyodrębniane i kodowane według typu
decltype
.Istnieje specjalny przepis, abyśmy mogli łatwiej pisać użyteczny kod. Kiedy aplikujemy
decltype
do nazwy zmiennej (członkowskiej), zwykle nie chcemy jakiegoś typu, który reprezentuje właściwości zmiennej, gdy jest traktowany jako wyrażenie. Zamiast tego chcemy tylko typu, za pomocą którego deklarowana jest zmienna, bez konieczności stosowania do tego mnóstwa cech typu. I to jest dokładnie to, codecltype
mamy nam dać.Jeśli zależy nam na właściwościach zmiennej jako wyrażeniu, nadal możemy ją dość łatwo uzyskać za pomocą dodatkowej pary nawiasów.
źródło
int
członkai
za
,decltype(a.i)
jestint
natomiastdecltype((a.i))
toint&
(zakładając, żea
nie jestconst
)? Skoro wyrażeniea.i
można przypisać?a.i
jest nie stałą wartością, więc otrzymujesz typ odniesienia dla wartości stałej(a.i)
.&
, xvalues są&&
, a prvalues nie są typami referencyjnymi.W wersjach wcześniejszych niż C ++ 11 język potrzebuje narzędzi, aby uzyskać dwa różne rodzaje informacji :
Ze względu na charakter tych informacji funkcje musiały zostać dodane w języku (nie można tego zrobić w bibliotece). Oznacza to nowe słowa kluczowe. Standard mógł wprowadzić do tego dwa nowe słowa kluczowe. Na przykład,
exprtype
aby uzyskać typ wyrażenia idecltype
uzyskać typ deklaracji zmiennej. To byłaby jasna, szczęśliwa opcja.Jednak komitet standardowy zawsze starał się unikać wprowadzania nowych słów kluczowych w języku, aby zminimalizować uszkodzenie starego kodu. Kompatybilność wsteczna jest podstawową filozofią języka.
Więc z c ++ 11 mamy tylko jedno słowo kluczowe używany dla dwóch różnych rzeczy:
decltype
. Różnice między tymi dwoma zastosowaniami polega na tym, że traktujemydecltype(id-expression)
inaczej. Była to świadoma decyzja komitetu, (mały) kompromis.źródło
export
został wprowadzony. Jeśli możeszexport
(wcześniej wszystkie szablony były domyślnie „eksportowane”), możesz mieć takie rzeczy jakdecltype
iconstexpr
. Oczywiście dodanieregister
w innym języku byłoby problematyczne.