2013-02-24 10 views
35

Ich erhalte unerwartete Ergebnisse aus allen Compilern, auf denen habe ich versucht, die folgende (GCC 4.7.2, 4.8.0 GCC beta, 13.0.1 ICC, Clang 3.2, VC10):Was ist das Ergebnis von decltype ("Hallo")?

#include <type_traits> 

int main() 
{ 
    // This will fire 
    static_assert(
     std::is_same<decltype("Hello"), char const[6]>::value, 
     "Error!" 
     ); 
} 

Ich hätte erwartet die Kompilierung Assertion über nicht zu feuern, aber es tut. Schließlich hat dieser nicht (wie erwartet):

#include <type_traits> 

int main() 
{ 
    char const hello[6] = "Hello"; 

    // This will not fire 
    static_assert(
     std::is_same<decltype(hello), char const[6]>::value, 
     "Error!" 
     ); 
} 

Also, was ist das Ergebnis decltype("Hello") nach dem C++ 11 Standard (Referenzen sehr geschätzt werden)? Was soll ich damit vergleichen, damit die obige Assertion zur Kompilierungszeit nicht ausgelöst wird?

Antwort

29

[Hinweis: Ursprünglich sollte dies keine selbstbeantwortete Frage sein; Ich fand die Antwort zufällig selbst, während ich meine Versuche zu untersuchen beschrieb, und ich dachte, es wäre schön gewesen, sie zu teilen.]

nach Anhang C (2.14.5) des C++ 11 Standard:

Der Typ einer Stringliteral ist aus „array of char“ auf „Array von const char „[....]

Außerdem Ziffer 7.1.6.2/4 gibt an (über das Ergebnis decltype).

Der Typ von decltype(e) bezeichnet ist wie folgt definiert:

- wenn e ein unparenthesized id-Ausdruck oder ein unparenthesized Klassenmitglied Zugang (5.2.5), decltype(e) ist die Art der durch e benannte Entität. Wenn es keine solche Entität gibt oder e eine Gruppe überladener Funktionen benennt, ist das Programm schlecht formatiert.

- Andernfalls, wenn ein e xValue ist, decltype(e)T&& ist, wo die Art der Te ist;

- Andernfalls, wenn e ein L-Wert ist, ist decltype(e)T&, wo T ist die Art der e;

- sonst ist decltype(e) der Typ e.

Da string literals are lvalues nach dem obigen Absatz und der Absatz aus Anhang C, wobei das Ergebnis decltype("Hello") ist ein lvalue Bezug auf ein Array der Größe 6 von konstant schmalem Zeichen:

#include <type_traits> 

int main() 
{ 
    // This will NOT fire 
    static_assert(
     std::is_same<decltype("Hello"), char const (&)[6]>::value, 
     "Error!" 
     ); 
} 

Schließlich, obwohl die hello Variable ist auch ein Lvalue, die zweite Kompilierung Assertion aus dem Text der Frage doe s nicht Feuer, weil hello ist ein unparenthesized ID-Ausdruck, die es in den ersten Punkt der obigen Liste aus Absatz 7.1.6.2/4 fallen. Daher ist das Ergebnis decltype(hello) der Typ der Entität, die von hello benannt wird, die char const[6] ist.

+0

Diese Regeln machen Sinn, wenn Sie über 'declltype (expr) &&' schreiben. –

+1

@KerrekSB: Ja. Ich fand es einfach überraschend, weil ich irgendwie gewohnt bin, grob zu denken "ein String-Literal hat den Typ" const char [] ',' declltype (x) 'gibt den Typ von' x' zurück, also 'declltype (" hallo ")' sollte 'const char [6]' "zurückgeben und dabei die Details vergessen. Lektion gelernt (hoffentlich) –

+3

+1 sowohl auf die Frage und die Antwort. Ich verspreche, dass ich nie mehr einen C++ - Compiler anfasse. –