Another one for the language lawyers.
For the following code, regardless of whether the explicit instantiation of A<int>
is present:
clang 3.0 requires typename
in the declaration of Type1
and Type3
, but not of Type2
.
gcc 4.8.1 requires typename
in the declaration of Type1
, but not of Type2
or Type3
.
struct C
{
int f1();
static int f2();
int m;
};
template<int i>
struct S
{
typedef int Type;
};
template<typename T>
struct B : C
{
};
template<typename T>
struct A : B<T>
{
void f()
{
typedef typename S<sizeof(C::f1())>::Type Type1; // typename required
typedef S<sizeof(C::f2())>::Type Type2; // typename not required
typedef typename S<sizeof(C::m)>::Type Type3; // typename not required?
}
};
template struct A<int>;
I figure typename
is required in the declaration of Type1
because the implied object argument for a call to a nonstatic member is (*this)
, the type of which is dependent.
See [over.call.func]:
In unqualified function calls, the name is not qualified by an
->
or.
operator and has the more general form of a primary-expression. The name is looked up in the context of the function call following the normal rules for name lookup in function calls. The function declarations found by that lookup constitute the set of candidate functions. Because of the rules for name lookup, the set of candidate functions consists (1) entirely of non-member functions or (2) entirely of member functions of some class T. In case (1), the argument list is the same as the expression-list in the call. In case (2), the argument list is the expression-list in the call augmented by the addition of an implied object argument as in a qualified function call. If the keywordthis
is in scope and refers to classT
, or a derived class ofT
, then the implied object argument is(*this)
.
Following this logic, typename
is not required in the declaration of Type2
because the member is static. Nor is typename
required in the declaration of Type3
because the expression is not a call to a nonstatic member.
I've read through this: Where and why do I have to put the "template" and "typename" keywords? .. and through the rules in [temp.dep.type] and [temp.dep.expr]. I can't see anything that specifies whether a nonstatic member function name should be given special treatment when determining if an expression is dependent. Does the standard specify this?
EDIT: removed discussion of transformation into class member access expressions based on [class.mfct.non-static] - Casey's answer discusses this in much greater detail.
&C::f1
would be a valid expression. – Casey