2

オーバーロードされた += 演算子を使用して、C# に似たデリゲートを使用するテンプレート クラス Delegate があります。

// ... generalized version of the template omitted from code
template<typename... TArgs>
    class Delegate<void, TArgs...>
    {
        private:
            using Func = std::function<void(TArgs...)>;
            std::vector<Func> funcs;

        public:
            template<typename T> Delegate& operator+=(T mFunc) { funcs.push_back(Func(mFunc)); return *this; }
            void operator()(TArgs... mParams) { for (auto& f : funcs) f(mParams...); }
    };

これは私がやろうとしていることです:

struct s
{
    void test() { }
    void run()
    {
        Delegate<void> d;
        d += [] { /* do something */ ; };
        d += test; // does not compile
    }
};

d += test;仕事を許可する方法はありますか?

4

3 に答える 3

3
void test(int x, int y) { return x - y; }

どのようにコンパイルできますか?この関数は何も返さないはずです。その戻り値の型はvoid.

また、プライマリ テンプレートを定義 (または宣言) したと仮定します。

template<typename R, typename... TArgs>
class Delegate;

またdelegate、クラス テンプレートはDelegate.

とにかく、test何も返さないので、問題なくコンパイルできます:

http://stacked-crooked.com/view?id=c56b7a2e758f8fbc361228834c90822b


member-function-pointers に関しては、現在の実装ではサポートされていません。非静的メンバ関数ポインタは の形式を取ることに注意してくださいR (C::*MemPtr)(Args...) cv。ただそれに取り組んでください。

于 2013-01-13T21:58:20.383 に答える
1

メンバー関数も、機能するオブジェクトのインスタンスを必要とします。を使用して関数を抽出する場合は、最初のパラメータとして指定できます。また、を使用std::mem_fnして現在のオブジェクトを関数にバインドすることもできます。std::bind

コードはそれを明確にします:

struct s
{
    void test() { }
    void run()
    {
        Delegate<void> d;
        d += [] { /* do something */ ; };
        d += std::bind(std::mem_fn(&s::test), this); // does compile
    }
};

の方法がよくわかりませんd += test。あなたは本当に実際のオブジェクトを渡す必要があります。このラムダバージョンは、現在のオブジェクトが必要であることをさらに明確に示しています。

struct s
{
    void test() { }
    void run()
    {
        Delegate<void> d;
        d += [this] { test(); };
    }
};

もちろん、operator+=行でこれを割り当てる必要はありません。以下のようにコンストラクターDelegateを取り込むように変更するか( )、またはテスト関数を追加できるプロキシオブジェクトを提供するメンバー関数を追加することができます():(私はこれらをテストしませんでした)thisrunv1runv2

struct s
{
    void test() { }
    void runv1()
    {
        Delegatev2<s, void> d(this);
        d += test;
    }
    void runv2()
    {
        Delegate<void> d;
        auto memd = d.getMemberDelegate(this);
        memd += test;
    }
};
于 2013-01-13T22:21:07.130 に答える
0

Nawazが編集で述べたように、メンバー(非satic)関数を使用します。これは、std :: functionのvoid()署名と互換性がありません。

2つの解決策:

  • 次のようなものを使用しますstd::function<void(s&)>
  • メンバー関数をオブジェクトにバインドしますstd::bind(&s::test,&s);(K-balloが言ったように、Csqはそうしました)

さらに、完全な転送を実現するには、rrefとstd::forwardを使用する必要があります。

于 2013-01-13T22:25:55.787 に答える