对于模板参数推导的真正工作原理,我从来没有得到很好的解释,所以我不确定如何解释我在下面看到的行为:
template<typename T>
struct Base
{
protected:
template<bool aBool = true>
static void Bar(int)
{
}
};
template<typename T>
class Derived : public Base<T>
{
public:
void Foo() { Base<T>::Bar<false>(5); }
};
int main()
{
Derived<int> v;
v.Foo();
return 0;
}
此代码无法构建,并给出错误:
main.cpp: In instantiation of 'void Derived<T>::Foo() [with T = int]':
main.cpp:25:8: required from here main.cpp:19:15: error: invalid
operands of types '<unresolved overloaded function type>' and 'bool'
to binary 'operator<'
如果您更改 2 Base<T>
s 派生到 Base<int>
,它编译。如果您将调用更改为 Bar()
至 Base<T>::template Bar<false>(5);
,它也会编译。
我看到的对此的解释是,编译器不知道 Bar 是一个模板,大概是因为在声明 Derived 的特化之前它不知道 Base 是什么。但是一旦编译器开始为 Foo()
生成代码, Base<T>
已经被定义,Bar
的类型可以确定。是什么导致编译器假定符号 Bar
不是模板,正在尝试应用 operator<()
相反?
我假设它与编译过程中何时评估模板的规则有关——我想我正在寻找的是对这个过程的一个很好的综合解释,这样下次我遇到像这样的代码时下面,我可以在没有堆栈溢出的好人帮助的情况下推断出答案。
请注意,我正在使用 g++ 4.7 进行编译,支持 c++x11。
最佳答案
void Foo() { Base<T>::Bar<false>(5); }
在此背景下 Base<T>
是从属名称。要访问依赖名称的成员模板,您需要添加 template
关键词:
void Foo() { Base<T>::template Bar<false>(5); }
否则Base<T>::Bar
将被解析为非模板成员和 <
作为小于。
至于为什么 template
是必需的,原因是两阶段查找。该错误是在第一遍期间触发的,在类型被替换之前,因此编译器不知道 Base<T>
的定义是什么.例如,考虑您添加了 Bar
的特化对于 int
有一个非模板 Bar
成员(例如 int
成员)。替换前 T
进入Foo
,编译器不知道该类型是否有专门化。
关于c++ - 模板化静态成员函数是如何解析的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12848155/