1

我正在尝试创建一个模板函数,它接受指向成员函数(非虚拟)的指针。我正在使用 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 的函数。

谢谢!

4

2 回答 2

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

于 2012-10-17T11:31:40.297 回答
0

据我所知,您必须使用不需要的版本。

template<class A, class B>
void caller(A &a, void (B::*func)()) {
    (a.*func)();
}

因为该函数未在该对象上定义,因此类型解析不能干净地应用。

但我一般不建议使用这种类型的回调示意图。要么使用良好的旧 C 风格回调;带有void*数据指针或类似sigc++的函数。

sigc++ 的巨大优势是您拥有可以绑定到几乎任何东西、函数、方法或函数以及所有类型安全的通用信号。

(请原谅,这不是对您问题的直接回答,而是关于如何更进一步的提示。)

于 2012-10-17T12:07:00.420 回答