Confusing Template error
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?
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>()
.
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.
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.
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".
精彩评论