Search code examples
c++c++11decltype

Why is decltype(class::class::class::member) valid


I noticed by accident that this code compiles and works correctly:

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

Why is this correct (decltype(M::M::M::M::some_int) <=> decltype(M::some_int))?

What other constructs one can use this pattern with class::class::...::member?

Compiler: Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23824.1 for x86


Solution

  • This works because of the injected-class-name:

    (N3337) [class]/2:A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name. For purposes of access checking, the injected-class-name is treated as if it were a public member name. [...]

    So you can arbitrarily nest these, and they'll work with derived types as well:

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

    Note that in the case of A[::A]*::A, the injected-class-name can be considered to name the constructor instead:

    [class.qual]/2: In a lookup in which the constructor is an acceptable lookup result and the nested-name-specifier nominates a class C:

    — if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C (Clause 9), or

    — [...]

    the name is instead considered to name the constructor of class C.