Confusing Template error

32,919

Solution 1

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

Solution 2

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.

Solution 3

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

Solution 4

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.

Share:
32,919
Admin
Author by

Admin

Updated on August 03, 2020

Comments

  • Admin
    Admin almost 4 years

    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?

  • Admin
    Admin almost 14 years
    I would have never been able to guess that... but thank you ;-). there is clearly always something to learn about C++!
  • Johannes Schaub - litb
    Johannes Schaub - litb almost 14 years
    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).
  • Admin
    Admin almost 14 years
    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...
  • Doug
    Doug almost 14 years
    @Johannes Schaub - litb: Right, so it's more a problem of assigning consistent semantic meaning to the expression, than it is of looking ahead.
  • Matthieu M.
    Matthieu M. over 13 years
    Now that's a devilish example!
  • Violet Giraffe
    Violet Giraffe over 9 years
    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.
  • Johannes Schaub - litb
    Johannes Schaub - litb over 9 years
    @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
    Johannes Schaub - litb over 9 years
    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.
  • Violet Giraffe
    Violet Giraffe over 9 years
    @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.
  • Curious
    Curious over 8 years
    Could you maybe comment on why this is the case? Why would C++ require this sort of syntax?
  • Enrico Borba
    Enrico Borba about 4 years
    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.