#include <iostream>
void foo()
{
std::cout << "global foo()" << std::endl;
}
struct A {
void foo()
{
std::cout << "A::foo()" << std::endl;
}
};
struct B : public A {
void call()
{
foo();
}
};
int main(int argc, char **argv )
{
B b;
b.call();
return 0;
}
这会给expected result:
A::foo()
然而,在更改两行(B类到模板)之后:
#include <iostream>
void foo()
{
std::cout << "global foo()" << std::endl;
}
struct A {
void foo()
{
std::cout << "A::foo()" << std::endl;
}
};
template <typename T> // change here
struct B : public T {
void call()
{
foo();
}
};
int main(int argc, char **argv )
{
B<A> b; // and here
b.call();
return 0;
}
global foo()
使用this->
不是一个选项,因为我正在尝试创建一个&#34;后备&#34;机构。
答案 0 :(得分:16)
您得到的是预期结果。这在C ++标准中称为“两阶段名称查找”。
模板内的名称分为两种类型:
依赖 - 依赖于模板参数但未在模板中声明的名称。
非依赖 - 不依赖于模板参数的名称,以及模板本身的名称和在其中声明的名称。
当编译器尝试解析代码中的某个名称时,它首先会确定该名称是否依赖,并且解析过程源于此区别。虽然非依赖名称是“正常”解析的 - 当定义模板时,依赖名称的解析发生在模板实例化的时刻。
示例中foo();
中的 B::call
是非依赖名称,因此在模板定义时将其解析为全局foo()
。
答案 1 :(得分:3)
接受的答案解释了为什么你会看到这种行为,而不是如何实现&#34;后备&#34;你想要的行为。这可以通过引入一对成员模板重载来使用SFINAE来完成,其中一个重载仅在基类具有名为foo
的成员函数时才存在。
template <typename T>
struct B : T {
template <void (T::*)()> struct has_mem_fn {};
template <typename U> void call(has_mem_fn<&U::foo>*) {this->foo();}
template <typename U> void call(...) {foo();}
void call() {call<T>(0);}
};
struct X {};
int main()
{
B<A> ba;
ba.call(); // A::foo()
B<X> bx;
bx.call(); // global foo()
}
更新:我刚刚在另一个答案中注意到您的评论,您说您已经了解此方法,但由于必须支持功能失调的编译器,因此无法使用它。在那种情况下,我担心你想要的东西可能是不可能的。
答案 2 :(得分:0)
你需要具体告诉使用T类方法。
template <typename T>
struct B : public T {
void call()
{
T::foo();
}
};
但是对于后备机制,您可以查看以下问题:Is it possible to write a template to check for a function's existence?
使用替换失败不是错误(SFINAE),您可以在T中检查方法foo
,然后运行正确的方法。