2016-06-06 13 views
8

zauważyłem przez przypadek, że ten kod kompiluje i działa poprawnie:Dlaczego decltype (klasa klasa :: :: :: członkiem klasy) ważny

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

Dlaczego jest to poprawne (decltype(M::M::M::M::some_int) <=> decltype(M::some_int))?

Jakie inne konstrukcje można użyć tego wzoru z class::class::...::member?

Compiler: Microsoft (R) C/C++ Compiler Wersja 19.00.23824.1 Optymalizacja dla x86

+1

Och, chłopcze, załóżcie, że upiory wpadają w coś, co oczywiście jest [duplikatem] (http://stackoverflow.com/q/12135498). –

Odpowiedz

9

Działa powodu wtryskiwany klasy I nazwą :

(N3337) [class]/2: Klasa nazwa dodaje się do zakresu, w którym została zadeklarowana natychmiast po nazwa klasy jest widziany. Nazwa klasy jest również wstawiana do zakresu samej klasy; jest to znane jako nazwa klasy wtryskiwanej. Do celów sprawdzania dostępu nazwa klasy wtryskiwanej jest traktowana tak, jakby była to nazwa publiczna. [...]

Więc można dowolnie gniazdo nich, a oni będą pracować z typów pochodnych, a także:

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

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

pamiętać, że w przypadku A[::A]*::A, wstrzyknięta-nazwa-klasy można uznać wymienić konstruktora zamiast:

[class.qual]/2: w przeglądowych w którym konstruktor jest akceptowalny wynik wyszukiwania, i zagnieżdżona nazwa-specyfikator wyznacza klasy C

- gdy nazwa określonego po zagnieżdżonej-NAME specyfikacją, gdy ogląda się C jest wtryskiwany klasy nazwa z C (Rozdział 9) lub

- [...]

nazwa jest zamiast tego uznawana za nazwę konstruktora klasy C.

+2

* "Zauważ, że w przypadku' A [:: A] * :: A', nazwa klasy wtryskiwanej może być uznana za nazwę konstruktora: "* Ib4 naturalna kontynuacja dupe: Yes, clang zwykle to źle. Zobacz np. [this] (https://stackoverflow.com/questions/29681449/program-being-compiled-różnie-in-3-major-c-compilers-which-one-is-right). –

10

To jest ważne we wszystkich kontekstach, nie tylko decltype. Klasa zawiera własną nazwę jako nazwa klasy wstrzykiwanej . Tak więc w klasie A::B::M nazwa M jest wstrzykiwana w odniesieniu do klasy A::B::M. Oznacza to, że możesz wtedy użyć M::M::M::some_member, aby odnieść się do członków tej klasy, jeśli naprawdę chcesz.

[Live example]

Zauważ, że gdy odnosi się tylko do samej nazwy klasy (np M::M::M), sytuacja jest nieco inna. Jeśli takie odniesienie wystąpi w miejscu, w którym odniesienie do funkcji może być potencjalnie poprawne, składnia jest brana za odwołanie do konstruktora. Jednak w kontekstach typu tylko takie odwołanie jest poprawne. Przykład:

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 
{}; 
Powiązane problemy