2

C++でデリゲートを「管理」するクラスを作成しようとしています。私はすでにデリゲートクラスを実装しています。私はこのデリゲートマネージャークラスは2つの機能を持つようにしたい:メンバ関数の可変長テンプレート付きポインタ

  • 一つは、与えられた入力引数/戻り値の型を特定の型のデリゲートのインスタンスへのポインタを取り、それをキャッシュします。

  • 他の関数は、キャッシュされたデリゲートインスタンスをバインドするために、正しいタイプのメンバ関数を使用します。現在

、私が持っている:

template<typename... Args> 
struct FunctionParamsPack { }; 

これは、この関数が取るパラメータの型のコンテナです。すなわちfoo(int i, double d)についてはintおよびdoubleとなる。私はhereの助言に従っています。

、私はDelegateInfoPackクラスがある:

template<typename FuncRetType,typename... FuncParams> 
struct DelegateInfoPack{ 
    //for look-up by components in the program 
    typedef typename DelegateClass<FuncRetType, FuncParams...>   _Delegate; 
    //for the delegate manager 
    typedef typename FuncRetType          _FuncRetType; 
    typedef typename FunctionParamsPack<FuncParams...>     _FuncParams; 
}; 

この構造体は、それによってプログラムのコンポーネントが含まれ、それはDelegateMangerクラスで使用される2つが3つの型名、型定義される:

template<typename DelegateInfoPack> 
class DelegateManager 
{ 

typedef typename DelegateInfoPack::_Delegate   _Delegate; 

typedef typename DelegateInfoPack::_FuncRetType  _FuncRetType; 
typedef typename DelegateInfoPack::_FuncParams  _FuncParams; 


void CacheDelegate(_Delegate* del,...) {} 

template<typename UserClass> 
void BindDelegate(..., _FuncRetType(UserClass::*fp)(_FuncParams())) {} //Doesn't work! 

} 

私の問題は、BindDelegate()の機能です。私は与えられた戻り値の型と入力パラメータ型を持つ型のメンバ関数の正しい署名を作成できません。

基本的には、私のBindDelegateが引数として受け取るように、与えられた戻り値の型と引数の型を持つ正しい関数ポインタ型を持つ方法を知る必要があります。

+0

なぜstd :: functionを使用しないのですか? – Evgeniy

+0

@Evgeniy私はそれらに精通していません。デモを気にしますか? – ShS

答えて

2

一つのアプローチは、部分的な特殊化を使用することです:

を:

template<typename> class DelegateManager; 

template<typename FuncRetType,typename... FuncParams> 
class DelegateManager<DelegateInfoPack<FuncRetType,FuncParams...>> 
{ 
    template<typename UserClass> 
    void BindDelegate(_FuncRetType(UserClass::*fp)(FuncParams...)) 
    { 
    } 
}; 

別のアプローチは、あなたのBindDelegateのメンバ関数でそれを使用すると、適切な関数型を生成するクラス

template <typename FuncRetType,typename FuncParams> 
struct FunctionPointer; 

template <typename FuncRetType,typename...ARGS> 
struct FunctionPointer<FuncRetType,FunctionParamsPack<ARGS...>> { 
    typedef FuncRetType (Type)(ARGS...); 
}; 

を持つことです

また、これをあなたのDelegateInfoPackクラスに入れることもできます:

template<typename FuncRetType,typename... FuncParams> 
struct DelegateInfoPack { 
    . 
    . 
    . 
    typedef FuncRetType (_FuncType)(FuncParams...); 
}; 

とあなたのタスクを解決するための追加的な方法として、そのあなたのDelegateManagerで

template<typename DelegateInfoPack> 
struct DelegateManager 
{ 
    . 
    . 
    . 

    typedef typename DelegateInfoPack::_FuncType _FuncType; 

    template<typename UserClass> 
    void BindDelegate(_FuncType UserClass::*fp) 
    { 
    } 
}; 
+0

私は現在のデザインを維持することを好む。実際には、私のパラメータ型の格納方法と、メンバ関数のポインタ型のシグニチャでそれらを "呼び戻す"方法が間違っているかどうかを知りたいです。 – ShS

+0

@ user4376555:パラメータパックを展開するには、パックが有効である必要がありますので、何かを変更する必要があります。それを行うにはさまざまな方法があります。保存したいデザインのどの側面をより具体的にすることができますか? –

+0

ああ、私は参照してください。現在、DelegateInfoPackは2つの目的を果たしています。つまり、DelegateInfoPacksを含むヘッダーによってコンポーネントがDELEGATE_TYPE delを持つことができるように、デリゲートタイプをtypedefします。彼らは後でデリゲートマネージャーに渡すことができます。第2に、すべての情報をまとめてDelegateManagerクラスをきれいにするちょっとした方法です。私が望んでいたように「きれいに」保つことができないように聞こえる。私は "友達"と一緒に遊んでみましたが、それはどちらもうまくいきませんでした。私はDelegateInfoPackをシンナーにしてFuncParamsを取り除かなければならないと思う。 – ShS

1

を使用する - C++ 11は、標準的な要素

を使用して、あなたのコードをより柔軟にすることができる新しい言語機能が導入されました
#include <iostream> 
#include <functional> 
#include <tuple> 
#include <iostream> 

using std::cout; 
using std::endl; 
using namespace std::placeholders; 

// helpers for tuple unrolling 
template<int ...> struct seq {}; 
template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {}; 
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; }; 

// simple function 
double foo_fn(int x, float y, double z) 
{ 
    return x + y + z; 
} 

// structure with memner function to call 
struct foo_struct 
{ 
    // member function to be used as a delegate 
    double foo_fn(int x, float y, double z) 
    { 
     return x + y + z; 
    } 
    // this member function has different signature - but it can be used too 
    // please note that argument order is changed too 
    double foo_fn_4(int x, double z, float y, long xx) 
    { 
     return x + y + z + xx; 
    } 
}; 

// delegate class that holds as delegate as its params for future call 
template <typename Ret, typename ...Args> 
struct delayed_call 
{ 
    // tuple can be used as FunctionParamsPack type 
    typedef std::tuple<Args...> params_type; 
    // std::function as delegate type 
    typedef std::function<Ret(Args...)> function_type; 

    // stored parameters 
    params_type params; 
    // stored delegate 
    function_type func; 

    // invocation 
    Ret operator()() 
    { 
    return callFunc(typename gens<sizeof...(Args)>::type()); 
    } 
    // direct invocation 
    Ret operator()(Args... args) 
    { 
    return func(args...); 
    } 

    // internal invocation with tuple unrolling 
    template<int ...S> 
    double callFunc(seq<S...>) 
    { 
    return func(std::get<S>(params) ...); 
    } 
}; 

int main(void) 
{ 
    // arguments 
    std::tuple<int, float, double> t = std::make_tuple(1, 5, 10); 
    // var #1 - you can use simple function as delegate 
    delayed_call<double, int,float, double> saved_foo_fn{t, foo_fn}; 
    foo_struct fs; 
    // var #2 - you can use member function as delegate 
    delayed_call<double, int,float, double> saved_foo_fn_struct{t, std::bind(&foo_struct::foo_fn, fs, _1, _2, _3)}; 
    // var #3 - you can use member function with different signature as delegate. 
    // bind 0 to xx and change argument order 
    delayed_call<double, int,float, double> saved_foo_fn_struct_4{t, std::bind(&foo_struct::foo_fn_4, fs, _1, _3, _2, 0l)}; 
    // var #4 - you can use lambda function as delegate 
    delayed_call<double, int,float, double> saved_lambda{t, [](int x, float y, double z) 
    { 
     return x + y + z; 
    } 
    }; 
    cout << "saved_foo_fn: " << saved_foo_fn() << endl; 
    cout << "saved_foo_fn_struct: " << saved_foo_fn_struct() << endl; 
    cout << "saved_foo_fn_struct_4: " << saved_foo_fn_struct_4() << endl; 
    cout << "saved_lambda: " << saved_lambda() << endl; 
    cout << "direct call with (1,2,3) to a member: " << saved_foo_fn_struct(1, 2, 3) << endl; 
} 

出力:

saved_foo_fn: 16 
saved_foo_fn_struct: 16 
saved_foo_fn_struct_4: 16 
saved_lambda: 16 
direct call with (1,2,3) to a member: 6 

Live demo

だからのみメンバ関数と限定されず、また、プレースホルダた場合でも、別の署名で

を任意の呼び出し可能なタイプを使用することができます:: _ 1 ...あなたのための醜い - there is a solution

関連する問題