16

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?

Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • A full and complete answer to this question can be found in the Comeau C++ Templates FAQ entry, ["What is the `->template`, `.template` and `::template` syntax about?"](http://www.comeaucomputing.com/techtalk/templates/#templateprefix). – James McNellis Aug 17 '10 at 03:52
  • 1
    I'm stuck… §5.2.5/1 says "A postfix expression followed by a dot . or an arrow ->, **optionally followed by the keyword template (14.8.1)**, and then followed by an id-expression, is a postfix expression." But 14.8.1 appears to be unrelated, aside from describing how C++ is able to resolve member function templates *without* the keyword. Where is this keyword specified? – Potatoswatter Aug 17 '10 at 04:01
  • @Potatoswatter: The keyword is specified in §2.11 Table 3, of course. ;-) (On a more serious note, that's a good question). – James McNellis Aug 18 '10 at 04:07

3 Answers3

41

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
  • 134,909
  • 25
  • 265
  • 421
  • +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 Aug 18 '10 at 04:45
  • What about ambiguity in closing > ? For example the case `x->foo < T::bar > (3) > (4);` – Ajay Brahmakshatriya Apr 10 '19 at 17:08
  • @AjayBrahmakshatriya For that there’s the typename keyword. – Potatoswatter Apr 11 '19 at 05:32
  • @Potatoswatter I am not sure how typename would help here. Suppose `T::bar` is known to be of type `int` and `foo` takes a template argument of type `int`. It is unclear whether the template argument is `T::bar > (3)` and a call with argument `(4)` or the template argument is `T::bar` and the argument is `(3)`. Then the result of the call is compared with `(4)`. – Ajay Brahmakshatriya Apr 11 '19 at 21:59
  • @AjayBrahmakshatriya If it’s any type at all, then the expression takes grammatical precedence and > is an operator. Only if typename is used, then > is a delimiter. – Potatoswatter Apr 12 '19 at 02:01
9

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
  • 24,777
  • 4
  • 73
  • 129
0

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

Max Lybbert
  • 19,717
  • 4
  • 46
  • 69