I was reading the Wikipedia article on SFINAE and encountered following code sample:
struct Test
{
typedef int Type;
};
template < typename T >
void f( typename T::Type ) {} // definition #1
template < typename T >
void f( T ) {} // definition #2
void foo()
{
f< Test > ( 10 ); //call #1
f< int > ( 10 ); //call #2 without error thanks to SFINAE
}
Now I've actually written code like this before, and somehow intuitively I knew that I needed to type "typename T" instead of just "T". However, it would be nice to know the actual logic behind it. Anyone care to explain?
In general, C++'s syntax (inherited from C) has a technical defect: the parser MUST know whether something names a type, or not, otherwise it just can't solve certain ambiguities (e.g., is
X * Y
a multiplication, or the declaration of a pointer Y to objects of type X? it all depends on whether X names a type...!-). Thetypename
"adjective" lets you make that perfectly clear and explicit when needed (which, as another answer mentions, is typical when template parameters are involved;-).Basically, you need the
typename
keyword when you are writing template code (i.e. you are in a function template or class template) and you are referring to an indentifier that depends on a template parameter that might not be known to be a type, but must be interpreted as a type in your template code.In your example, you use
typename T::Type
at definition #1 becauseT::Type
depends on the template parameterT
and might otherwise be a data member.You don't need
typename T
at definition #2 asT
is declared to be a type as part of the template definition.The short version that you need to do
typename X::Y
whenever X is or depends on a template parameter. Until X is known, the compiler can't tell if Y is a type or a value. So you have to addtypename
to specify that it is a type.For example:
As sbi points out in the comments, the cause of the ambiguity is that
Y
might be a static member, an enum or a function. Without knowing the type ofX
, we can't tell. The standard specifies that the compiler should assume it is a value unless it is explicitly labelled a type by using thetypename
keyword.And it sounds like the commenters really want me to mention another related case as well: ;)
If the dependant name is a function member template, and you call it with an explicit template argument (
foo.bar<int>()
, for example), you have to add thetemplate
keyword before the function name, as infoo.template bar<int>()
.The reason for this is that without the template keyword, the compiler assumes that
bar
is a value, and you wish to invoke the less than operator (operator<
) on it.