2017-09-19 6 views
0

私は、コールバック関数を登録し、後でこのように呼び出すクラスを持っています。クラステンプレートからラムダを生成する

template<typename ReturnType, typename... Args> 
class Signal { 
    std::vector<std::function<ReturnType(Args...)>> function; 
public: 
    template<typename... Args2> 
    ReturnType operator()(Args2&&... args2) { 
     ReturnType ret; 
     for (auto& func : function) 
      ret = func(std::forward<Args2>(args2)...); 
     return ret; 
    } 

    template<typename Func> 
    void func(Func const &func) { 
     function.push_back(std::function<ReturnType(Args...)>(func)); 
    } 

    template<typename Class, typename Instance> 
    void mfunc(ReturnType(Class::*func)(Args...), Instance &instance) { 
     mfunc2(func, instance, make_int_sequence<sizeof...(Args)>{}); 
    } 
    template<typename Class, typename Instance, int... I> 
    void mfunc2(ReturnType(Class::*func)(Args...), Instance &instance, int_sequence<I...>) { 
     using namespace std::placeholders; 
     function.push_back(std::function<ReturnType(Args...)>(std::bind(func, &instance, placeholder_template<I>{}...))); 
    } 
}; 

#include <iostream> 

class foo { 
public: 
    int bar(int x, double y) { 
     std::cout << x << " and " << y << std::endl; 
     return x*2; 
    } 
}; 

int main() { 
    foo foo1; 
    Signal<int, int, double> sig; 
    sig.mfunc(&foo::bar, foo1); 
    std::cout << "Return: " << sig(5,5.5) << std::endl; 
} 

今日はステファン・T. Lavavejから話を聞いた、と彼は言っていたことの一つは、STD ::バインドは避け、代わりにラムダを使用しなければならないということです。新しいことを学ぶために、私はmfunc2のstd :: bind呼び出しをラムダに変更しようと考えていましたが、テンプレートが新しく、必要なコードを生成する方法を理解できません。

私はSOにここで見つけるmake_int_sequenceで現在placeholder_templateが、私は実際にそれ上の任意の良い読書を見つける方法を正確にそれが動作、またはどこの周り私の頭をラップすることはできません...

のArgs ...ラムダが受け入れるべき引数型を保持していますが、sizeof ...(Args)に応じてvar1、var2、var3などの変数名を作成し、それらを一緒にマージする必要があります。

たとえば、< int、int、int>、Args ...はint、intを保持します。 は、私は、私はこれを達成する可能性がどのように

[func, &instance](int var1, int var2) -> ReturnType { return func(&instance, var1, var2); } 

としてラムダを構築したいですか?これは、仕事をする必要があります

+0

[mcve]で始まります。コンパイルしたものを使って、バリデーションラムダを使用するように変更する方法を示すことができます。 – AndyG

+0

テンプレート指定子を削除するために私の投稿を編集しました。したがって、戻り値の型(voidではない)と少なくとも1つの引数を指定する限り、コンパイルする必要があります。 – super

答えて

1

template<typename ReturnType, typename... Args> 
class Signal { 
    std::vector<std::function<ReturnType(Args...)>> function; 
public: 
    template<typename... Args2> 
    ReturnType operator()(Args2&&... args2) { 
     ReturnType ret; 
     for (auto& func : function) 
      ret = func(std::forward<Args2>(args2)...); 
     return ret; 
    } 

    template<typename Func> 
    void func(Func const &func) { 
     function.push_back(std::function<ReturnType(Args...)>(func)); 
    } 

    template<typename Class, typename Instance> 
    void mfunc(ReturnType(Class::*func)(Args...), Instance& instance) { 
     function.push_back([&instance, func](Args&&... args) { 
      return (instance.*func)(std::forward<Args>(args)...); 
     }); 
    } 

}; 

https://ideone.com/gjPdWN

注意、あなたは基本的には最後のものを除き、すべての戻り値を捨てて、あなたのオペレータで()という。その行動は意図されていますか?

+0

素晴らしい!まさに私が探していたもの。そして、はい、唯一の戻り値を除いてすべてを放棄することが意図されています。私は値がstd :: vector に置かれ、それを返すことができると思うが、もし私が必要ならば、それらの行に沿って何かを行うだろう。 – super

関連する問題