非类型模板函数指向const成员函数

时间:2012-06-18 19:56:56

标签: c++ const function-pointers

我正在编写一个委托类,但它无法获取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成员函数转换为非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成员函数,使用非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),一切正常,但我宁愿使用一个函数。

那么,任何人都可以指出我做错了什么以及我如何能够做到这一点?

THX!

3 个答案:

答案 0 :(得分: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)这确实有效,但不是你想要的。

希望这有帮助!

答案 1 :(得分:1)

使用VS2010支持的std::bind或lambdas,以及std::function,这对您来说将不再是一个问题。

答案 2 :(得分: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);
但是,这有点乱。重载解决方案更好! : - )