Search code examples
c++templatestypenamedependent-name

typename keyword and nested name specifier


struct A{};

template <typename T>
struct B
{
    typename ::A a1; //(1)
    typename A a2; //(2): error
};

int main(){return 0;}

Why is the first case correct, but the second isn't? I don't understand the meaning of that restriction.
And anyway, why is the first case allowed? ::A isn't template-parameter dependent name. What's meaning in it?


Solution

  • As @MikeSeymour's answer explains, going strictly by the standard (C++11, I don't have a C++14 text on hand), case (1) should actually be erroneous as well - typename prefixing a qualified name can only be used when there's at least one name on the left-hand side of the ::.

    However, as pointed out by @hvd in the comments, CWG issue 382 indicates the actual intent is to allow typename before any qualified name, including global-namespace qualification. Since this is what most compilers seem to implement, the rest of this answer follows with this idea.

    When viewed like this, it's not that case (2) is a restriction, it's that case (1) is benevolence. The required rule (and its very original wording, I believe) is basically that "if a qualified name which depends on template parameters denotes a type, you must prefix it with typename." For convenience, it is loosened to "typename can be used for any qualified name which dentoes a type, whether it's dependent or not."(1)

    In contrast, an unqualified name can never be ambiguous as to whether it refers to a type or not, so it never requires typename and typename is therefore not allowed there.


    (1)This loosening is not really explicitly stated in the standard, but follows from the combination of several rules. Basically, wherever a simple-type-specifier (something which denotes a type) is allowed, the grammar also allows a typename-specifier (a qualified name prefixed with typename). The rules for templates (mainly in 14.6) only state that typename is required when a dependent qualified name denotes a type. Since nothing forbids typename in other contexts, it can be used with any qualified name which denotes a type (even outside of template context).