views:

120

answers:

4

I made the following program

#include <iostream>
#include <typeinfo>
template<class T>
struct Class
{
    template<class U>
    void display(){

        std::cout<<typeid(U).name()<<std::endl;
        return ;
    }

};


template<class T,class U>
void func(Class<T>k)
{
    k.display<U>(); 

}

int main()
{
    Class<int> d;
    func<int,double>(d);
}

The above program doesn not compile because display() is a template member function so a qualification of .template before display() must be done. Am I right?

But when I made the following program

#include <iostream>
#include <typeinfo>

template<typename T>
class myClass
{
    T dummy;
    /*******/
public:
    template<typename U>
    void func(myClass<U> obj);

};

template<typename T>
template<typename U>

void myClass<T>::func(myClass<U> obj)
{
    std::cout<<typeid(obj).name()<<std::endl;
}
template<class T,class U>
void func2(myClass<T>k)
{
    k.template func<U>(k); //even it does not compile

}
int main()
{
    myClass<char> d;
    func2<char,int>(d);
    std::cin.get();
}

Why k.func<char>(k); does not compile even after giving a .template construct?

A: 

The standard requires the template or typename keywords to disambiguate things that depend on the template context.

Max Lybbert
A: 

The first example compiles and runs fine for me in VS 2010.

Jesse Collins
+6  A: 

Section 5.1 of C++ Templates explains this construct in detail

The below function has a problem

template<class T,class U> 
void func2(myClass<T> k) 
{ 
    k.template func<U>(k); //even it does not compile 

} 

Here T = char and U = int

myclass<char>::func<int>(myclass<char>) 

is being called. However such a function does not exist

Even though in normal circumstances 'char' is convertible to 'int', this does not hold good for explicitly specified template arguments

Chubsdad
+2  A: 

The < symbol means both "less than" and "begin template arguments." To distinguish between these two meanings, the parser must know whether the preceding identifier names a template or not.

For example consider the code

template< class T >
void f( T &x ) {
    x->variable < T::constant < 3 >;
}

Either T::variable or T::constant must be a template. The function means different things depending which is and which isn't:

  1. either T::constant gets compared to 3 and the Boolean result becomes a template argument to T::variable<>
  2. or T::constant<3> gets compared to x->variable.

The to disambiguate, the template keyword is required before either variable or constant. Case 1:

template< class T >
void f( T &x ) {
    x->template variable < T::constant < 3 >;
}

Case 2:

template< class T >
void f( T &x ) {
    x->variable < T::template constant < 3 >;
}

It would be kind of nice if the keyword were only required in actual ambiguous situations (which are kind of rare), but it makes the parser much easier to write and it prevents such problems from catching you by surprise.

For standardese, see 14.2/4:

When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.

Potatoswatter
+1 for the first example: that is a really great code snippet for demonstrating the context sensitivity of the C++ grammar and why these keywords are needed.
James McNellis