2012-06-18 63 views
4

我正在寫一個委託類,但它無法使用const成員函數。 下面是測試情況:現在的編譯器(Visual Studio 2010中)給了我,他不能在const成員函數轉換爲非const函數錯誤非類型模板函數指向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); 
} 

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' 

OK,容易修復(我雖然: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 *)' 

如果我要重命名第二個呼叫功能(用const),這一切工作正常,但我寧願使用一個功能。

那麼,任何人都可以指出我做錯了什麼,我該如何做到這一點?

Thx!

+0

這*應該*工作,告訴MS他們錯了。 – Erik

回答

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)這是行得通的,但不是你想要的。

希望這會有所幫助!

+0

Thx爲答案!這在我的測試用例中完美地工作,但現在我的委託類不再編譯(試圖採用l值引用的'&'),但這是一個完全不同的問題,並且與此問題無關:) – moiself

1

使用std::bind或lambda,VS2010支持,和std::function,這將不再是你的問題。

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); 

這是一個有點亂,但。超載解決方案更好! :-)