1
votes

Both clang 3.6 and gcc 5.0 require typename in the following example:

template<typename T>
struct B
{
    typedef int Type;
};

void f(int);

template<int n>
struct A
{
    typedef typename B<decltype(f(n))>::Type Type;
};

This is covered by the following wording in the C++11 standard:

[temp.dep.type]/5

A name is a member of an unknown specialization if it is

  • A qualified-id in which the nested-name-specifier names a dependent type that is not the current instantiation.

[temp.dep.type]/8

A type is dependent if it is

  • a member of an unknown specialization,

  • a simple-template-id in which either the template name is a template parameter or any of the template arguments is a dependent type or an expression that is type-dependent or value-dependent

  • denoted by decltype(expression), where expression is type-dependent

This suggests B<decltype(f(n))>::Type is type-dependent only if B<decltype(f(n))> is type-dependent. Also that B<decltype(f(n))> is dependent only if f(n) is type-dependent.

[temp.dep.expr]/1

Except as described below, an expression is type-dependent if any subexpression is type-dependent.

[temp.dep.expr]/3

An id-expression is type-dependent if it contains

  • an identifier associated by name lookup with one or more declarations declared with a dependent type,

  • a template-id that is dependent,

  • a conversion-function-id that specifies a dependent type, or

  • a nested-name-specifier or a qualified-id that names a member of an unknown specialization;

or if it names a static data member of the current instantiation that has type “array of unknown bound of T” for some T

This suggests f(n) is type-dependent only if n is type-dependent, and that n is not type-dependent.

Am I missing something, or is this a compiler bug?

1
The same behaviour occurs when substituting f(n) with *new int(n) which is not type-dependent according to [temp.dep.expr]/3willj

1 Answers

2
votes

Your analysis is a little bit incomplete, but otherwise correct.

When a qualified-id is intended to refer to a type that is not a member of the current instantiation (14.6.2.1) and its nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword typename, forming a typename-specifier.

Clearly B<…>::Type cannot refer to a member of the current instantiation. So the question is whether B<decltype(f(n))> is a dependent type.

A type is dependent if it is

  • […]
  • a member of an unknown specialization,
  • […]
  • a simple-template-id in which either the template name is a template parameter or any of the template arguments is a dependent type or an expression that is type-dependent or value-dependent, or
  • denoted by decltype(expression), where expression is type-dependent (14.6.2.2).

f(n) isn't type-dependent as no sub-expression is, hence decltype(f(n)) isn't a dependent type.
Also, decltype(...) cannot be value-dependent as it isn't a constant expression1 and no other paragraph in [temp.dep.constexpr] applies. Clearly decltype(f(n)) isn't type-dependent either.
And least but not last, B<decltype(f(n))>::Type would be a member of an unknown specialization only if the template argument was a dependent type2, which we concluded it isn't.

So by my interpretation the compilers are incorrect and the typename keyword is not required.


1 In fact, decltype(…) is not an expression at all.

2 [temp.dep.type]/5:

A name is a member of an unknown specialization if it is

  • A qualified-id in which the nested-name-specifier names a dependent type that is not the current instantiation.
  • A qualified-id in which the nested-name-specifier refers to the current instantiation, the current instantiation has at least one dependent base class, and name lookup of the qualified-id does not find any member of a class that is the current instantiation or a non-dependent base class thereof.
  • An id-expression denoting the member in a class member access expression (5.2.5) in which either
    • […]