我正在尝试创建一个接受指向成员函数(非虚拟)的指针的模板函数。我正在使用MSVC2010
当有问题的行被注释掉时,以下代码有效。编译器报告的错误很明确,但我想知道仍然令人惊讶。您如何建议解决此问题。
谢谢!
class Foo{
public:
virtual void doFoo() {
std::cout << "In foo" << std::endl;
}
};
class Bar : public Foo{
public:
void doBar() {
std::cout << "In bar" << std::endl;
}
};
template<class A>
void caller(A &a, void (A::*func)()) {
(a.*func)();
}
int _tmain(int argc, _TCHAR* argv[])
{
Bar bar;
bar.doFoo();
caller(bar, &Bar::doBar);
caller(bar, &Bar::doFoo); // this line causes a compiler error
}
此错误导致以下错误。
error C2782: 'void caller(A &,void (__thiscall A::* )(void))' : template parameter 'A' is ambiguous
1> c:\test\test\test.cpp(23) : see declaration of 'caller'
1> could be 'Foo'
1> or 'Bar'
我可以通过将来电者更改为
来解决错误template<class A, class B>
void caller(A &a, void (B::*func)()) {
(a.*func)();
}
但是在考虑重载分辨率时,这会引入其他微妙的分辨率错误。理想情况下,我只想考虑实际可以应用于A的函数。
谢谢!
答案 0 :(得分:2)
您可以使用SFINAE来限制第二个模板的适用性
template<class A, class B>
void caller(A &a, void (B::*func)(), typename std::enable_if<std::is_base_of<B, A>::value, void>::type* =0)
这样,重载将不会引起导致编译错误的参数。有关参考,请参阅std::is_base_of
。
答案 1 :(得分:0)
据我所知,你必须使用不需要的版本。
template<class A, class B>
void caller(A &a, void (B::*func)()) {
(a.*func)();
}
因为没有在该对象上定义该函数,因此类型解析不能完全应用。
但我通常不会建议使用这种类型的回调原理图。要么使用好的旧C风格回调;使用void*
数据指针或类似sigc++的函数。
sigc ++的巨大优势在于你拥有可以绑定到几乎任何东西,函数,方法或函数以及所有类型安全的通用信号。
(请原谅这不是你问题的直接答案,而是提示如何进一步解决问题。)