1

メンバー関数(非仮想)へのポインターを受け入れるテンプレート関数を作成しようとしています。私はMSVC2010で作業しています

次のコードは、問題のある行がコメント化されている場合に機能します。コンパイラによって報告されたエラーはかなり説明的ですが、どういうわけかそれでも驚くべきことだと思います。この問題を回避することをどのように推奨しますか。

ありがとう!

class Foo{ 
public:
    virtual void doFoo() {
        std::cout << "In foo" << std::endl;
    }
};

class Bar : public Foo{ 
public:
    void doBar() {
        std::cout << "In bar" << std::endl;
    }

};

template<class A>
void caller(A &a, void (A::*func)()) {
    (a.*func)();
}

int _tmain(int argc, _TCHAR* argv[])
{
    Bar bar;
    bar.doFoo();
    caller(bar, &Bar::doBar);
    caller(bar, &Bar::doFoo); // this line causes a compiler error
}

これは次のエラーで失敗します。

error C2782: 'void caller(A &,void (__thiscall A::* )(void))' : template parameter 'A' is ambiguous
1>          c:\test\test\test.cpp(23) : see declaration of 'caller'
1>          could be 'Foo'
1>          or       'Bar'

発信者をに変更することでエラーを回避できます

template<class A, class B>
void caller(A &a, void (B::*func)()) {
    (a.*func)();
}

ただし、これにより、過負荷の解決を検討するときに、他の微妙な解決のバグが発生します。理想的には、実際にAに適用できる関数のみを検討したいと思います。

ありがとう!

4

2 に答える 2

2

SFINAEを使用して、2番目のテンプレートの適用を制限できます。

template<class A, class B>
void caller(A &a, void (B::*func)(), typename std::enable_if<std::is_base_of<B, A>::value, void>::type* =0)

このように、オーバーロードは、そうでなければコンパイルエラーを引き起こすパラメータの邪魔になりません。参考までに、を参照してくださいstd::is_base_of

于 2012-10-17T11:31:40.297 に答える
0

私が見る限り、あなたは不要なバージョンを使用しなければなりません。

template<class A, class B>
void caller(A &a, void (B::*func)()) {
    (a.*func)();
}

関数がそのオブジェクトに定義されていないため、型の解決が適切に適用されないためです。

しかし、私は通常、このタイプのコールバック回路図を使用することをお勧めしません。古き良きCスタイルのコールバックを使用してください。void*データポインタまたはsigc++のようなもので機能します。

sigc ++のモンスターの利点は、ほとんどすべてのもの、関数、メソッド、またはファンクター、およびすべてのタイプセーフにバインドできる汎用シグナルがあることです。

(これはあなたの質問に対する直接の答えではなく、それをさらに進める方法のヒントであることを許してください。)

于 2012-10-17T12:07:00.420 に答える