2

私の前の質問に動機付けられました: 任意のファンクターを取り、入力ファンクターの各戻り値のタプルを返す variadic 関数を作成します

ここで、void を返す可能性のある各関数オブジェクトを実行するだけのクラスを作成したいと考えています。私の知る限りでは、次のようなものを作成できます。

class A
{
public:
    template <class Func>
    void operator()(Func func)
    {
        func();
    }

    template <class First, class... Funcs>
    void operator()(First first, Funcs... funcs)
    {
        first();
        operator()(funcs...);
    }
};

このコードは仕事をします。Nawazただし、mfontanini上記のリンクのコードのように、もっと賢い方法があるに違いないと思います。

私は以下のコードを模倣してみました。

class A
{
public:
    template <class... Func>
    void operator()(Func func...)
    {
        func()...;
    }
};

ただし、gcc 4.7.2 はコンパイルされません。私はここに行方不明ですか?

4

2 に答える 2

4

Nawaz の回答を拡張するには、パック拡張を実行するための特定のコンテキストが必要です。どこでも実行できるわけではありません。これらのコンテキストの 1 つは関数の引数であり、もう 1 つは初期化の場合は任意の種類です。

Nawaz が提供したsink関数は良い出発点ですが、重大な欠陥があります。ファンクタが実行される順序が保証されていません。ユーザーが渡された順序を信頼できるようにしたい場合は、左から右への評価を保証するコンテキストが必要です。配列の初期化とリストの初期化の両方がここに適合します。

配列の初期化の使用:

template <class... Func>
void operator()(Func func...)
{
    int ignored[] = { (func(),0)... };
    (void)ignored; // silence unused variable warnings
}

リスト初期化の使用:

struct swallow{
  template<class... Ignored>
  swallow(Ignored&&...)
};

template <class... Func>
void operator()(Func func...)
{
    swallow{ (func(),0)... }; // create a temporary 'swallow' from all arguments
}

この(func(), 0)部分は単に を実行しfunc、戻り値があればそれを破棄してから、 に評価され0ます。

通常、戻り値の型に関係なく、任意のファンクターに対してこれを行い、結果を単に破棄する場合は、次のように記述します(void(func()), 0)...。このvoid(...)部分は、 からの戻り値がfunc()あれば、それを飲み込みます。これが必要なのは、ユーザーが をオーバーロードすることを許可されてoperator,おり、自分の型 and int(リテラルの型0) に対してオーバーロードすることを決定する可能性があるためです。ただし、どの側でも過負荷operator,にすることはできません。void

于 2013-02-25T07:50:09.847 に答える
3

あなたはこれを行うことができます:

template <class... Func>
void operator()(Func ... func) //corrected the syntax here
{
    sink( (func(),0)... );
}

は次のようにsink定義されます。

template<typename ...T> void sink(T...) {}

の目的は、返されるものに関係なくsink、式の値を食べることです。戻り値の型がであっても機能します。(func(),0)0func()func()void

上記のデモでは、最初の 2 つの関数は何かを返しますが、3 番目の関数は を返しますvoid

関数を左から右に呼び出す場合は、リスト初期化構文を使用できます。

 int sink[]{func(),0)... };

しかし、不必要にvariableを作成します。だから私はsink構造体として定義します:

struct sink
{
     template<typename ...T> 
     sink(T...) {}  //templated constructor!
};

これを使用すると、次のことができます。

sink { (func(),0)... }; //note the curly-braces now!

更新されたデモ:

それが役立つことを願っています。

于 2013-02-25T07:42:04.357 に答える