+9  A: 

When a dependent name is used to refer to a nested template, the nested name has to be prepended with the keyword template to help the compiler understand that you are referring to a nested template and parse the code correctly

template <typename T>
void F(A<T> &a)
{
    a.template f<0>();
}

Inside main the name a is not dependent, which is why you don't need the extra template keyword. Inside F name a is dependent, which is why the keyword is needed.

This is similar to the extra typename keyword when referring to nested type names through a dependent name. Just the syntax is slightly different.

AndreyT
+1  A: 

In the former, the compiler thinks that you mean...

a.f < 0 ...gibberish....

Andrey's answer fixes that.

Noah Roberts
A: 

Notice that there are code snippet that are valid for both the keyword added and not added, yielding different results in each case, even for templates that take type parameters instead of integers.

#include <iostream>

struct A { 
  template<typename T> 
  static A f(T) { 
    return A(); 
  } 

  template<typename T> operator T() { return T(); }
}; 

template<typename U> 
int g() { 
  U u;
  typedef A (*funcPtrType)(int());
  return !(funcPtrType)u.f < int() > (0); 
}

int main() {
  std::cout << g<A>() << std::endl;
}

This outputs 0 when run without the template keyword added. If you add the keyword before f < int() > it outputs 1.


Explanation

The version without the keyword parses as

funcPtrType temp1 = (funcPtrType)u.f; // taking func address
bool temp2 = !temp1;                  // temp2 == false
bool temp3 = temp2 < int();           // temp3 == false
bool temp4 = temp3 > (0);             // temp4 == false
return temp4;

And the version with the keyword parses as

A temp1 = u.template f < int() > (0);     // function call
funcPtrType temp2 = (funcPtrType) temp1;  // temp2 == 0
bool temp3 = !temp2;                      // temp3 == true
return temp3;

Notice that temp2 is a null pointer (produced by return T()). Whole different parses, and both are valid! This really needs a way to disambiguate - which is to insert the template keyword as appropriate.

Johannes Schaub - litb