4

我正在编写一个委托类,但它无法采用 const 成员函数。这是一个测试用例:

class foo
{
    public:
   void MemberFunction()
   {
         printf("non const member function\n");
   }

   void ConstMemberFunction() const
   {
           printf("const member function\n");
   }
};

template <class C, void (C::*Function)()>
void Call(C* instance)
{
       (instance->*Function)();
}

int main (int argc, char** argv)
{
       foo bar;
       Call<foo,&foo::MemberFunction>(&bar);
       Call<foo,&foo::ConstMemberFunction>(&bar);
}

现在编译器(visual studio 2010)给了我一个错误,他无法将 const 成员函数转换为非常量函数:

2>..\src\main.cpp(54): error C2440: 'specialization' : cannot convert from 'void (__cdecl foo::* )(void) const' to 'void (__cdecl foo::* const )(void)'
2>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
2>..\src\main.cpp(54): error C2973: 'Call' : invalid template argument 'void (__cdecl foo::* )(void) const'
2>          ..\src\main.cpp(37) : see declaration of 'Call'

好的,通过添加以下内容轻松修复(我虽然:P):

template <class C, void (C::*Function)() const>
void Call(C* instance)
{
    (instance->*Function)();
}

但现在编译器完全糊涂了(我也很困惑)。看起来他现在尝试将 const 函数用于非常量成员函数,将非常量函数用于 const 成员函数。

2>..\src\main.cpp(53): error C2440: 'specialization' : cannot convert from 'void (__cdecl foo::* )(void)' to 'void (__cdecl foo::* const )(void) const'
2>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
2>..\src\main.cpp(53): error C2973: 'Call' : invalid template argument 'void (__cdecl foo::* )(void)'
2>          ..\src\main.cpp(43) : see declaration of 'Call'
2>..\src\main.cpp(53): error C2668: 'Call' : ambiguous call to overloaded function
2>          ..\src\main.cpp(43): could be 'void Call<foo,void foo::MemberFunction(void)>(C *)'
2>          with
2>          [
2>              C=foo
2>          ]
2>          ..\src\main.cpp(37): or       'void Call<foo,void foo::MemberFunction(void)>(C *)'
2>          with
2>          [
2>              C=foo
2>          ]
2>          while trying to match the argument list '(foo *)'
2>..\src\main.cpp(54): error C2440: 'specialization' : cannot convert from 'void (__cdecl foo::* )(void) const' to 'void (__cdecl foo::* const )(void)'
2>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
2>..\src\main.cpp(54): error C2973: 'Call' : invalid template argument 'void (__cdecl foo::* )(void) const'
2>          ..\src\main.cpp(37) : see declaration of 'Call'
2>..\src\main.cpp(54): error C2668: 'Call' : ambiguous call to overloaded function
2>          ..\src\main.cpp(43): could be 'void Call<foo,void foo::ConstMemberFunction(void) const>(C *)'
2>          with
2>          [
2>              C=foo
2>          ]
2>          ..\src\main.cpp(37): or       'void Call<foo,void foo::ConstMemberFunction(void) const>(C *)'
2>          with
2>          [
2>              C=foo
2>          ]
2>          while trying to match the argument list '(foo *)'

如果我重命名第二个 Call 函数(使用 const),一切正常,但我宁愿使用一个函数。

那么,任何人都可以指出我做错了什么以及如何使这项工作有效吗?

谢谢!

4

3 回答 3

3

我认为您可以通过从模板类型签名中删除函数指针并依赖重载来解决此问题:

template <class C>
    void Call(C* ptr, void (C::*function)()) {
    (ptr->*function)();
}
template <class C>
    void Call(C* ptr, void (C::*function)() const) {
    (ptr->*function)();
}

这现在使用正常的函数重载来选择应该调用两个函数中的哪一个。 const成员函数指针将向下调用到第二个版本,而非函数指针将const向上调用到第一个版本。这也意味着您不需要显式地向模板函数提供任何类型信息;编译器可以C在这两种情况下进行推断。

如果 (1) 这不起作用或 (2) 这确实有效,但不是您想要的,请告诉我。

希望这可以帮助!

于 2012-06-18T20:01:43.447 回答
1

使用std::bindVS2010 支持的 or lambdas,std::function这将不再是您的问题。

于 2012-06-18T20:15:49.017 回答
0

您的问题是成员函数指针与 const 成员函数指针的类型不同。我将您的Call功能修改为:

template< typename C, typename funcptr_t, funcptr_t ptr >
void Call( C *instance )
{
  (instance->*ptr)();
}

现在使用附加的模板参数,我可以这样称呼它:

Call<foo,void (foo::*)(),&foo::MemberFunction>(&bar);
Call<foo,void (foo::*)() const, &foo::ConstMemberFunction>(&bar);

不过,这有点乱。重载解决方案更好!:-)

于 2012-06-18T21:22:57.643 回答