我一直玩clang一段时间,我偶然发现了"test/SemaTemplate/dependent-template-recover.cpp"(在clang发行版中),它应该提供从模板错误中恢复的提示.
整个过程可以很容易地删除到最小的例子:
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>();
}
};
Run Code Online (Sandbox Code Playgroud)
clang产生的错误消息:
tpl.cpp:6:13: error: use 'template' keyword to treat 'f0' as a dependent template name
t->f0<U>();
^
template
1 error generated.
Run Code Online (Sandbox Code Playgroud)
...但我很难理解究竟应该插入template
关键字以使代码在语法上正确?
Pra*_*rav 85
ISO C++ 03 14.2/4:
当成员模板专业化的名称出现之后.或 - >在postfix-expression中,或在qualified-id中的nested-name-specifier之后,postfix-expression或qualified-id显式依赖于template-parameter(14.6.2),成员模板名称必须是以关键字模板为前缀.否则,假定该名称命名非模板.
In t->f0<U>();
f0<U>
是一个成员模板特化,它出现在后面->
并明确依赖于模板参数U
,因此成员模板特化必须以template
关键字为前缀.
所以t->f0<U>()
改为t->template f0<U>()
.
Joh*_*itb 24
除了其他人提出的观点之外,请注意有时编译器无法下定决心,并且两种解释都可以在实例化时产生其他有效的程序.
#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;
}
Run Code Online (Sandbox Code Playgroud)
0
在省略template
之前f<int()>
但1
在插入时打印.我把它留作练习来弄清代码的作用.
Dou*_*oug 10
在插入符号的位置之前插入它:
template<typename T, typename U, int N> struct X {
void f(T* t)
{
t->template f0<U>();
}
};
Run Code Online (Sandbox Code Playgroud)
编辑:如果您像编译器一样思考,此规则的原因会变得更清晰.编译器通常只能一次向前看一个或两个令牌,并且通常不会"向前看"表达式的其余部分.[编辑:请参阅注释]关键字的原因与您需要typename
关键字指示依赖类型名称的原因相同:它告诉编译器"嘿,您将看到的标识符是模板的名称,而不是静态数据成员的名称后跟一个小于号的符号".
摘自C++模板
.template构造在引入typename之后发现了一个非常类似的问题.请考虑使用标准bitset类型的以下示例:
template<int N>
void printBitset (std::bitset<N> const& bs)
{
std::cout << bs.template to_string<char,char_traits<char>,
allocator<char> >();
}
Run Code Online (Sandbox Code Playgroud)
这个例子中的奇怪构造是.template.如果没有额外使用模板,编译器就不会知道后面的小于令牌(<)实际上并不是"小于",而是模板参数列表的开头.请注意,仅当句点之前的构造取决于模板参数时,才会出现此问题.在我们的示例中,参数bs取决于模板参数N.
总之,.template表示法(以及类似符号,如 - >模板)应仅在模板内使用,并且只有在它们遵循依赖于模板参数的内容时才使用.