C++ 令人困惑的模板错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3786360/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Confusing Template error
提问by Prasoon Saurav
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.
我一直在玩 clang,我偶然发现了“test/SemaTemplate/dependent-template-recover.cpp”(在 clang 发行版中),它应该提供从模板错误中恢复的提示。
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:
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?
...但我很难理解到底应该在哪里插入template
关键字以使代码在语法上正确?
回答by Prasoon Saurav
ISO C++03 14.2/4:
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.
当成员模板特化的名称出现在 . 或 -> 在后缀表达式中,或在限定 id 中的嵌套名称说明符之后,并且后缀表达式或限定 id 显式依赖于模板参数(14.6.2),成员模板名称必须是以关键字 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.
Int->f0<U>();
f0<U>
是一个成员模板特化,它出现在后面->
并且显式依赖于模板参数U
,因此成员模板特化必须以template
关键字为前缀。
So change t->f0<U>()
to t->template f0<U>()
.
所以t->f0<U>()
改为t->template f0<U>()
.
回答by Johannes Schaub - litb
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.
这0
在template
之前省略f<int()>
但1
插入时打印。我把它作为一个练习来弄清楚代码的作用。
回答by Doug
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".
编辑:如果你像编译器一样思考,这条规则的原因就会变得更清楚。编译器通常一次只向前看一两个标记,并且通常不会“向前看”表达式的其余部分。[编辑:见评论]关键字的原因与为什么需要typename
关键字来指示依赖类型名称的原因相同:它告诉编译器“嘿,您将要看到的标识符是模板的名称,而不是后跟小于号的静态数据成员的名称”。
回答by Chubsdad
Excerpt from C++ Templates
摘自C++ 模板
The .template Construct A very similar problem was discovered after the introduction of typename. Consider the following example using the standard bitset type:
.template Construct 引入 typename 后发现了一个非常相似的问题。考虑以下使用标准位集类型的示例:
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.
这个例子中奇怪的结构是 .template。如果没有额外使用模板,编译器就不会知道后面的小于标记 (<) 并不是真正的“小于”,而是模板参数列表的开始。请注意,仅当句点之前的构造依赖于模板参数时,这才是一个问题。在我们的示例中,参数 bs 取决于模板参数 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.
总之,.template 表示法(以及类似的表示法,例如 ->template)应该仅在模板内部使用,并且仅当它们遵循依赖于模板参数的某些内容时。