繁体   English   中英

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

[英]Non-type template function pointer to const member function

我正在编写一个委托类但它没有采用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),它一切正常,但我宁愿使用一个函数。

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

谢谢!

我想你可以通过从模板类型签名中删除函数指针而不是依赖重载来解决这个问题:

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)这确实有效,但不是你想要的。

希望这可以帮助!

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

您的问题是成员函数指针是一个不同于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);

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM