tags:

views:

333

answers:

4

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?

+11  A: 

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 add typename to specify that it is a type.

For example:

template <typename T>
struct Foo {
  typename T::some_type x; // T is a template parameter. `some_type` may or may not exist depending on what type T is.
};

template <typename T>
struct Foo {
  typename some_template<T>::some_type x; // `some_template` may or may not have a `some_type` member, depending on which specialization is used when it is instantiated for type `T`
};

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 of X, 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 the typename 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 the template keyword before the function name, as in foo.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.

jalf
jalf, it might be worth mentioning an alternative meaning of `T::something` (static data, function name). And once your at it so well, it might be worth to add the explanation for why sometimes we must inject a `template`, too. It has the same reason, so it won't take that much longer.
sbi
`template` isn't the same reasoning though. It has nothing to do with dependant names. It falls in the category of "problems that tend to trip you up with templates", but I don't think it's the same reason as with `typename`.
jalf
@jalf: Isn't it to do with template names? In any case, the reasons are pretty analogous. It's only allowed in template code and it has to be used to distinguish dependent member names that are names of templates from dependent member names that aren't.
Charles Bailey
Yes, you're right. I added it to my answer now. The reason I was reluctant to do so is that I wasn't 100% sure on the exact rules for when and why it is necessary. Let me know if I'm completely wrong in the above. ;)
jalf
+2  A: 

Take a look at this link: A Description of the C++ typename keyword

bdonlan
+3  A: 

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...!-). The typename "adjective" lets you make that perfectly clear and explicit when needed (which, as another answer mentions, is typical when template parameters are involved;-).

Alex Martelli
Do you mean "typically when template parameters are involved" (in which case I'm pretty sure it's *only* when template parameters are involved), or is that a typo for "which is typical when template parameters are involved"?
Steve Jessop
@onebyone, good catch, I did indeed mean "typical" and not "typically", edited my answer to fix, tx.
Alex Martelli
+3  A: 

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 because T::Type depends on the template parameter T and might otherwise be a data member.

You don't need typename T at definition #2 as T is declared to be a type as part of the template definition.

Charles Bailey