c++templateselaborated-type-specifier

type-dependent nested-name-specifier in elaborated-type-specifier


I never saw a nested-name-specifier in an elaborated-type-specifier before this question, and at first glance I thought it wasn't even covered by the grammar. Now I see that since C++98 up to the present, it's translated as a special case without the typename-specifier construct. C++11 7.1.6.3/2 (7.1.5.3/2 in C++98):

3.4.4 describes how name lookup proceeds for the identifier in an elaborated-type-specifier. If the identifier resolves to a class-name or enum-name, the elaborated-type-specifier introduces it into the declaration the same way a simple-type-specifier introduces its type-name.

Therefore it would seem that although you can form a qualified elaborated-type-specifier, you need to take care that it's never type-dependent. Name resolution per 3.4.4 at template definition time will never find a class-name because dependent names are presumed to be objects unless prefixed with the typename keyword, which isn't grammatically allowed in this context.

Is this an accurate assessment of the meaning of the standard, and the design intent of the language?


Solution

  • Expanding from the comments:

    Take this program as an example:

    template <typename T>
    struct S1 { struct I { }; };
    
    template <typename T>
    struct S2 { typedef struct S1<T>::I I; }; // okay
    
    template <typename T>
    struct S3 { typedef struct S2<T>::I I; }; // okay at definition time
                                              // usually error at instantiation time
    template <>
    struct S2<short> : S1<short> { };
    
    int main() {
      S1<int>::I a;
      S2<int>::I &b = a; // okay
      S3<int>::I &c = b; // error
      S1<short>::I d;
      S2<short>::I &e = d; // okay
      S3<short>::I &f = e; // okay
    }
    

    At template definition time, both S2 and S3 are okay: 14.6p5 lists the exceptions where typename is not required. Essentially: where the use is unambiguous because the name can never be anything other than a type, typename is not required. This includes several cases where typename is not syntactically allowed, so where requiring typename would mean there is no way to write the program. Both typename struct S<T>::I and struct typename S<T>::I are hard errors, and struct S<T>::I is unambiguous.

    At template instantiation time, the rules of 3.4.4 are clearer: both struct S1<int>::I and struct S2<int>::I can then be found, where it becomes apparent that S2<int>::I is a typedef, so struct S2<int>::I is an error. At the same time, at that point, S2<short>::I is seen not to be a typedef, but a struct, so struct S2<short>::I is allowed.