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 メンバー関数を非 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 *)'

2 番目の Call 関数の名前を (const を使用して) 変更すると、すべて正常に機能しますが、1 つの関数を使用することをお勧めします。

それで、誰かが私が間違っていることと、どうすればこれを機能させることができるかを教えてもらえますか?

どうも!

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

これは、通常の関数のオーバーロードを使用して、2 つの関数のどちらを呼び出すかを選択するようになりました。 constメンバー関数ポインターは 2 番目のバージョンまで呼び出されますが、非const関数は最初のバージョンまで呼び出されます。これは、型情報をテンプレート関数に明示的に提供する必要がないことも意味します。コンパイラはC両方のコンテキストで推測できます。

(1)これが機能しない場合、または(2)これは機能するが、あなたが望むものではない場合はお知らせください。

お役に立てれば!

于 2012-06-18T20:01:43.447 に答える
1

std::bindVS2010がサポートするまたはラムダを使用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 に答える