Error starting template

I played with clang for a while, and I came across "test / SemaTemplate / dependent-template-recover.cpp" (in the clang distribution), which should provide hints for recovering from a template error.

All this can be easily divided into 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 received 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 it's hard for me to understand where exactly one should insert the template keyword so that the code is syntactically correct?

+66
c ++ templates clang llvm
Sep 24 '10 at 10:59
source share
4 answers

ISO C ++ 03 14.2 / 4:

When then the member template specification appears. or β†’ in a postfix expression or after a nested qualifier name in identified-id, and postfix-expression or identified-id clearly depends on the template parameter (14.6.2), the participant’s template name must be the keyword template prefix . Otherwise, it is assumed that the name is called a non-pattern.

In t->f0<U>(); f0<U> is the member template specification that appears after -> and which clearly depends on the template parameter U , so the member template specialization must have a prefix with the template keyword.

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

+63
Sep 24 '10 at 11:14
source share

In addition to the ones made by other users, please note that sometimes the compiler could not solve, and both interpretations can give alternative valid programs when creating instances

 #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*)af<int()>(0); } int main() { std::cout << g<void>() << std::endl; } 

When printing, 0 when skipping template to f<int()> , but 1 when pasting. I leave this as an exercise to figure out what the code does.

+18
Sep 24 2018-10-10T00:
source share

Insert it immediately before the point where the carriage 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 usually look at only one or two tokens at a time and usually do not β€œlook to the future” at the rest of the expression. [Edit: see comment] The reason for the keyword is the same as why you need the typename keyword to specify dependent type names: it tells the compiler "Hey, the identifier you are about to see is the name of the template, not the name of the static member data than a sign. "

+7
Sep 24 '10 at 11:01
source share

Excerpt from C ++ Templates

.Template Design A very similar problem was discovered after typename was introduced. Consider the following example using the standard bit set 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 design in this example is .template. Without this additional use of the template, the compiler does not know that the smaller token (<) that follows is actually not "less", but the beginning of the list of template arguments. Please note that this is only a problem if the design before the period depends on the template parameter. In our example, the parameter bs depends on the template parameter N.

In conclusion, the .template notation (and similar entries such as β†’ template) should be used only within templates and only if they follow what depends on the template parameter.

+6
Sep 24 '10 at 11:11
source share



All Articles