4

不明なタイプの関数(たとえば、合意された名前を持つ関数を含む構造体の名前)に不透明なハンドルが渡され、その関数に引数を転送する関数を作成するとします。

非可変個引数の場合、単純化のために単一パラメーター関数を考慮すると、これを行うには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;
}

問題は、パラメータパックがテンプレート引数としてのみ自立することを許可されておらず、それらを囲んでいるテンプレートでラップした場合、パターンマッチングによってのみ、それらを所定の位置でアンラップおよびアンパックする方法がないことです。

「Upfront」には、自己文書化の改善や型推論のサポートの改善など、いくつかの利点があります(up_front <T>自体をdecltypeすることができます)。可変個引数の場合にそれを機能させる方法はありますか?(もちろん、std :: tupleを使用することもできますが、それはかなり満足のいくものではありません。)

4

2 に答える 2

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...);
    }
};

これからトップレベルの関数を作成する方法はないと思いますが(元の問題に再び遭遇します)、それはおそらくそれほど悪くはありません。

それでも他の解決策を見て喜んでいるでしょう。

于 2011-11-13T01:30:34.500 に答える
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;
}
于 2016-06-17T08:58:01.637 に答える