117

I've been playing with clang a while, and I stumbled upon "test/SemaTemplate/dependent-template-recover.cpp" (in the clang distribution) which is supposed to provide hints to recover from a template error.

The whole thing can be easily stripped down to a minimal example:

template<typename T, typename U, int N> struct X {
    void f(T* t)
    {
        // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}
        t->f0<U>();
    }
};

The error message yielded by clang:

tpl.cpp:6:13: error: use 'template' keyword to treat 'f0' as a dependent template name
         t->f0<U>();
            ^
            template 
1 error generated.

... But I have a hard time understanding where exactly one is supposed to insert the template keyword to have the code to be syntactically correct?

2
  • 13
    Did you try inserting it where the arrow is pointing? Commented Sep 24, 2010 at 11:28
  • 3
    Similar to this and this Commented Sep 24, 2010 at 11:32

4 Answers 4

147

ISO C++03 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.

In t->f0<U>(); f0<U> is a member template specialization which appears after -> and which explicitly depends on template parameter U, so the member template specialization must be prefixed by template keyword.

So change t->f0<U>() to t->template f0<U>().

Sign up to request clarification or add additional context in comments.

4 Comments

Interestingly, I thought putting the expression in parentheses: t->(f0<U>()) would have fixed that, as I thought that would put f0<U>() into standalone expression... well, I thought wrong, it seems...
Could you maybe comment on why this is the case? Why would C++ require this sort of syntax?
Yeah this is weird. The language can "detect" that the template keyword needs to be present. If it can do that then it should just "insert" the keyword in there itself.
I feel that this is a useless syntax feature....
32

In addition to the points others made, notice that sometimes the compiler couldn't make up his mind and both interpretations can yield alternative valid programs when instantiating

#include <iostream>

template<typename T>
struct A {
  typedef int R();

  template<typename U>
  static U *f(int) { 
    return 0; 
  }

  static int f() { 
    return 0;
  }
};

template<typename T>
bool g() {
  A<T> a;
  return !(typename A<T>::R*)a.f<int()>(0);
}


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

This prints 0 when omitting template before f<int()> but 1 when inserting it. I leave it as an exercise to figure out what the code does.

5 Comments

Now that's a devilish example!
I can't reproduce the behavior you're describing in Visual Studio 2013. It always calls f<U> and always prints 1, which makes perfect sense to me. I still don't understand why the template keyword is required and what difference it makes.
@Violet the VSC++ compiler is not a compliant C++ compiler. A new question is needed if you want to know why VSC++ always prints 1.
This answer explains why template is needed: stackoverflow.com/questions/610245/… without relying solely on standardese terms that are hard to understand. Please report if anything in that answer is still confusing.
@JohannesSchaub-litb: Thanks, a great answer. Turns out, I've read it before because it was already upvoted by me. Apparently, my memory is meh.
19

Excerpt from C++ Templates

The .template Construct A very similar problem was discovered after the introduction of typename. Consider the following example using the standard bitset type:

template<int N> 
void printBitset (std::bitset<N> const& bs) 
{ 
    std::cout << bs.template to_string<char,char_traits<char>, 
                                       allocator<char> >(); 
} 

The strange construct in this example is .template. Without that extra use of template, the compiler does not know that the less-than token (<) that follows is not really "less than" but the beginning of a template argument list. Note that this is a problem only if the construct before the period depends on a template parameter. In our example, the parameter bs depends on the template parameter N.

In conclusion, the .template notation (and similar notations such as ->template) should be used only inside templates and only if they follow something that depends on a template parameter.

Comments

14

Insert it just before the point where the caret is:

template<typename T, typename U, int N> struct X {
     void f(T* t)
     {
        t->template f0<U>();
     }
};

Edit: the reason for this rule becomes clearer if you think like a compiler. Compilers generally only look ahead one or two tokens at once, and don't generally "look ahead" to the rest of the expression.[Edit: see comment] The reason for the keyword is the same as why you need the typename keyword to indicate dependent type names: it's telling the compiler "hey, the identifier you're about to see is the name of a template, rather than the name of a static data member followed by a less-than sign".

3 Comments

Even with infinite look-ahead, you still will need template. There are cases where both with and without template will yield valid programs with different behavior. So this is not only a syntactical problem (t->f0<int()>(0) is valid syntactically for both the less-than and the template argument list version).
@Johannes Schaub - litb: Right, so it's more a problem of assigning consistent semantic meaning to the expression, than it is of looking ahead.
This is a very old thread, but it's raised its ugly head when compiling Eigen3 c++.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.