我发现当v.foo
从模板类型 () 的变量访问非模板属性 () 时T& v
,如果存在同名的模板函数 (),C++ 可能会被欺骗认为它是成员模板template class <T> void foo()
。如何从 C++ 规范中解释这一点?考虑这个简单的程序:
#include <cassert>
/** Determine whether the 'foo' attribute of an object is negative. */
template <class T>
bool foo_negative(T& v)
{
return v.foo < 0;
}
struct X
{
int foo;
};
int main()
{
X x;
x.foo = 5;
assert(!foo_negative(x));
return 0;
}
我们有一个模板函数foo_negative
,它接受任何类型的对象并确定其 foo 属性是否为负。该函数使用 [T = X] 进行main
实例化。foo_negative
该程序编译并运行,没有任何输出。
现在,将此函数添加到程序的顶部:
template <class T>
void foo()
{
}
用 G++ 4.6.3 编译它会导致这个编译器错误:
funcs.cpp: In function ‘bool foo_negative(T&)’:
funcs.cpp:13:14: error: parse error in template argument list
funcs.cpp: In function ‘bool foo_negative(T&) [with T = X]’:
funcs.cpp:25:5: instantiated from here
funcs.cpp:13:14: error: ‘foo’ is not a member template function
(其中第 13 行是return v.foo < 0
第 25 行assert(!foo_negative(x))
。)
Clang 会产生类似的错误。
笏?添加一个从未调用过的不相关函数如何将语法错误引入有效程序?解析foo_negative
时,编译器不知道 的类型v
,更重要的是,它不知道v.foo
是成员模板还是常规成员。显然,它必须在解析时(在模板实例化之前)决定是将其视为成员模板还是普通成员。
如果它认为v.foo
是成员模板,< 0
则被视为作为0
模板参数传递,并且缺少>
,因此出现语法错误。然后,当foo_negative
用 [T = X] 实例化时,还有另一个错误,因为X::foo
不是成员模板。
但是为什么它认为v.foo
是成员模板呢?这种歧义正是template
关键字的用途:如果我写了v.template foo
,那么我会明确告诉 C++ 期待一个成员模板,但我没有使用template
关键字!我没有提到成员模板,所以它应该假设它是一个普通成员。有一个与成员同名的函数这一事实不应该有任何影响。为什么会这样?它不可能是编译器中的错误,因为 GCC 和 clang 是一致的。