2016-06-06 19 views
8

ho notato per caso che questo codice compila e funziona correttamente:Perché decltype (classe :: :: classe classe :: membro) valida

struct M { int some_int; }; 
static_assert(std::is_same< 
        decltype(M::M::M::M::some_int) /* <- this */, 
        int>::value, "Types must be int"); 

Perché questo è corretto (decltype(M::M::M::M::some_int) <=> decltype(M::some_int))?

Quali altri costrutti si può utilizzare questo motivo con class::class::...::member?

compilatore: Microsoft (R) C/C++ compilatore di ottimizzazione Versione 19.00.23824.1 per x86

+1

Oh ragazzo ... i flussi di aggiornamento entrano per qualcosa che è ovviamente un [duplicato] (http://stackoverflow.com/q/12135498). –

risposta

9

Ciò funziona a causa della classe nome iniettato :

(N3337) [class]/2: A-nome di classe viene inserito nel campo di applicazione in cui è dichiarato immediatamente dopo il nome classe è visto. Anche il nome della classe viene inserito nell'ambito della classe stessa; questo è noto come nome della classe iniettata. Ai fini del controllo dell'accesso, il nome della classe immessa viene trattato come se fosse un nome membro pubblico. [...]

Così si può arbitrariamente nido questi, e lavoreranno con i tipi derivati ​​così:

struct A { using type = int; }; 
struct B : public A {}; 

using foo = B::B::B::A::A::A::type; 

Si noti che, nel caso di A[::A]*::A, the-class-name iniettato può essere considerato per citarne costruttore invece:

[class.qual]/2: in una ricerca in cui il costruttore è un risultato di ricerca accettabile e il nested-nome-specificatore nomina una classe C:

- se il nome specificato dopo il nested-nome-identificatore, quando alzò gli occhi in C, è la classe nome iniettato di C (Clausola 9), o

- [...]

il nome viene invece considerato per denominare il costruttore della classe C.

+2

* "Si noti che nel caso di' A [:: A] * :: A', il nome della classe immessa può essere considerato per nominare il costruttore invece: "* Ib4 il duplicato naturale del follow-up: Sì, clang tende a sbagliare. Vedi per es. [Questo] (https://stackoverflow.com/questions/29681449/program-being-compiled-differently-in-3-major-c-compilers-which-one-is-right). –

10

Questo è valido in tutti i contesti, non solo decltype. Una classe contiene il proprio nome come nome di classe iniettato . Quindi all'interno di una classe A::B::M, il nome M viene iniettato per fare riferimento alla classe A::B::M. Ciò significa che è possibile utilizzare M::M::M::some_member per fare riferimento ai membri di quella classe, se lo si desidera realmente.

[Live example]

Quando ci si riferisce solo al nome della classe stessa (ad esempio M::M::M), la situazione è leggermente diversa. Se tale riferimento si verifica in un punto in cui un riferimento a una funzione potrebbe anche essere potenzialmente corretto, la sintassi viene presa in riferimento al costruttore. Tuttavia, nei contesti di tipo solo, anche tale riferimento è valido. Esempio:

M::M::M m; // illegal, M::M interpreted as reference to constructor 

struct D : public M::M::M // legal, a function could not be references here, so M::M::M means M 
{};