2011-11-13 8 views
4

不明な型の関数に不透明なハンドルを渡す関数を記述したいとしましょう(例えば、合意した名前の関数を含む構造体の名前)、引数をその関数に転送します。C++ 11:variadic関数のパラメータ型の計算

単純化のために単一パラメータ関数を考えると、これを行うには2つの方法があります。フォワーディング関数に任意の型の引数を与え、それと転送関数を呼び出そうとすることができます。互換性がないと判明した場合、コンパイラはテンプレートの展開中に文句を言うでしょう。 decltypeやその他のさまざまなメカニズムを使って、転送先関数が期待するパラメータの種類を把握し、その型の引数を明示的に要求することができます。私はこれらの用語を受け入れているかどうかわからないので、私はそれらを "通過"と "前線"と呼ぶつもりです。

パススルー・メソッドは、任意の数のパラメータを持つ関数に直接的に一般化しますが、アップ・フロント・メソッドは一般化しません。

#include <iostream> 

template<typename T, typename Arg> 
void pass_through_1(Arg arg) 
{ 
    T::f(arg); 
} 

template<typename T> struct arg_of_1; 

template<typename Ret, typename Arg> 
struct arg_of_1<Ret (Arg)> 
{ 
    typedef Arg type; 
}; 

template<typename T> 
void up_front_1(typename arg_of_1<decltype(T::f)>::type arg) 
{ 
    T::f(arg); 
} 

template<typename T, typename... Args> 
void pass_through_var(Args... args) 
{ 
    T::f(args...); 
} 

template<typename T> struct args_of_var; 

template<typename...> struct type_list; 

template<typename Ret, typename... Args> 
struct args_of_var<Ret (Args...)> 
{ 
    // typedef Args... type; // can't do this 
    typedef type_list<Args...> type; 
}; 

// template<typename T> 
// void up_front_var(typename args_of_var<decltype(T::f)>::type... args) // can't do this 
// { 
//  T::f(args...); 
// } 

struct test 
{ 
    static void f(int x) { std::cout << x*9 << std::endl; } 
}; 

int main(int, char**) 
{ 
    pass_through_1<test>(7); 
    up_front_1<test>(8); 
    pass_through_var<test>(9); 
    // up_front_var<test>(10); 
    return 0; 
} 

問題は、パラメータパックがのみテンプレート引数として、自立をすることを許可されていないということです、そしてあなたが囲んでいるテンプレートでそれらをラップする場合は、場所でそれらを解凍アンラップ-と-する方法はありませんパターンマッチングによってのみ実行されます。

"Up front"には、より良い自己文書化、型推論のサポート(up_front <T>自体を宣言することができます)などの利点があります。それはvariadicの場合に動作させる方法はありますか? (もちろんstd :: tupleを使うこともできますが、これはむしろ満足できません)

+2

"up front"の欠点:オーバーロードされた関数またはデフォルトパラメータを処理できません。 – aschepler

+0

良い点。ユースケースによって異なります。 – glaebhoerl

答えて

1

答えを実現するために質問を書き留めるようなことはありません。

は、ここに1つの方法です:私はこれのうち、トップレベルの機能を(あなたは再び元の問題に実行する)ようにする方法はないと思う

template<typename T, typename Args = typename args_of_var<decltype(T::f)>::type> 
struct up_front_var; 

template<typename T, typename... Args> 
struct up_front_var<T, type_list<Args...>> 
{ 
    static void forward(Args... args) 
    { 
     T::f(args...); 
    } 
}; 

、それはおそらくあまりにも悪くはありません。

他の解決策を見ても幸いです。

0

おそらく私は質問を正しく理解していませんが、引数型を省略してコンパイラに推論させることができます。

/* declare */ 
template<typename T, typename... Args> 
void up_front_var(Args... args) 
{ 
    T::f(std::forward<Args>(args)...); // need std::forward to correctly handle lvalue/rvalue references 
} 

/* an example */ 
class Test { 
public: 
    static void f(const char* fmt, int a, int b); 
}; 

void Test::f(const char* fmt, int a, int b) 
{ 
    printf(fmt, a, b); 
} 


int main() 
{ 
    up_front_var<Test>("testing %u, %u", 1, 2); // no need to specify arguments here 
    return 0; 
} 
+0

はい、それは "パススルー"メソッドです。ほとんどの場合、何が問題になっているのですか(モジュロ 'std :: forward')。 – glaebhoerl

関連する問題