112

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?

Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • 12
    Did you try inserting it where the arrow is pointing? – Mike Seymour Sep 24 '10 at 11:28
  • 3
    Similar to [this](http://stackoverflow.com/questions/3691420/compiler-error-when-using-integer-as-template-parameter/) and [this](http://stackoverflow.com/questions/3621719/c-template-syntax) – Prasoon Saurav Sep 24 '10 at 11:32

4 Answers4

139

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>().

Marcus O Platts
  • 487
  • 5
  • 9
Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • 1
    Interestingly, I thought putting the expression in parentheses: `t->(f0())` would have fixed that, as I thought that would put `f0()` into standalone expression... well, I thought wrong, it seems... –  Sep 24 '10 at 11:32
  • 42
    Could you maybe comment on why this is the case? Why would C++ require this sort of syntax? – Curious Feb 13 '16 at 05:54
  • 11
    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. – Enrico Borba Jun 09 '20 at 17:07
  • I feel that this is a useless syntax feature.... – Virux Jul 30 '23 at 06:39
31

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.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 3
    Now that's a devilish example! – Matthieu M. Sep 28 '10 at 18:34
  • 1
    I can't reproduce the behavior you're describing in Visual Studio 2013. It always calls `f` 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 Giraffe Dec 23 '14 at 11:12
  • @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. – Johannes Schaub - litb Dec 24 '14 at 11:58
  • 2
    This answer explains why `template` is needed: https://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords without relying solely on standardese terms that are hard to understand. Please report if anything in that answer is still confusing. – Johannes Schaub - litb Dec 24 '14 at 11:59
  • @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. – Violet Giraffe Dec 24 '14 at 14:49
15

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.

Chubsdad
  • 24,777
  • 4
  • 73
  • 129
13

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".

Doug
  • 8,780
  • 2
  • 27
  • 37
  • 1
    I would have **never** been able to guess that... but thank you ;-). there is clearly always something to learn about C++! –  Sep 24 '10 at 11:06
  • 3
    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(0)` is valid syntactically for both the less-than and the template argument list version). – Johannes Schaub - litb Sep 24 '10 at 11:28
  • @Johannes Schaub - litb: Right, so it's more a problem of assigning consistent semantic meaning to the expression, than it is of looking ahead. – Doug Sep 24 '10 at 11:35