Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 982
Denis Avatar asked Dec 19 '22 08:12

Denis


2 Answers

The rule isn't that you can only use typename if the type is nested in a dependent scope. The rules are, more or less:

  • you must use typename if it's in a dependent scope
  • you can only use typename where it's allowed by the grammar.

The grammar allows it for a subset of qualified-id, specified by

typename-specifier:
    typename nested-name-specifier identifier
    typename nested-name-specifier template<opt> simple-template-id

nested-name-specifier:
    :: (C++14 or later)
    ::<opt> type-name ::
    ::<opt> namespace-name ::
    decltype-specifier ::
    nested-name-specifier identifier ::
    nested-name-specifier template<opt> simple-template-id ::

So the second case is certainly forbidden, since it doesn't involve any nesting. Strictly speaking, before C++14, the first was also forbidden, since a global qualifier :: didn't match that grammar.

like image 119
Mike Seymour Avatar answered Dec 22 '22 11:12

Mike Seymour


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).

like image 41
Angew is no longer proud of SO Avatar answered Dec 22 '22 11:12

Angew is no longer proud of SO