11

可変個引数テンプレートのパラメーターを初期化子リストで囲むと、それらが順番に評価されることが保証されますが、ここでは発生していません。

#include <iostream>
using namespace std;


template<class T> void some_function(T var)
{
   cout << var << endl;
}

struct expand_aux {
    template<typename... Args> expand_aux(Args&&...) { }
};

template<typename... Args> inline void expand(Args&&... args) 
{
   bool b[] = {(some_function(std::forward<Args>(args)),true)...}; // This output is 42, "true", false and is correct
   cout << "other output" << endl;
   expand_aux  temp3 { (some_function(std::forward<Args>(args)),true)...  }; // This output isn't correct, it is false, "true", 42
}

int main()
{
   expand(42, "true", false);

   return 0;
}

どうして?

4

2 に答える 2

4

前述のとおり、問題はコンパイラのバグです。コードは、書かれているように、その引数を順番に評価する必要があります。

私のアドバイスは、何をしたいのか、どの順序でそれを行っているのかを明示し、コンマ演算子の乱用を避けることです (余談ですがsome_function、オーバーライドする型が返されるとコードが奇妙に動作する可能性がありますoperator,) または初期化リストを使用する保証(これは標準的ですが、比較的あいまいです)。

私の解決策は、書いてから使用することdo_in_orderです:

// do nothing in order means do nothing:
void do_in_order() {}
// do the first passed in nullary object, then the rest, in order:
template<typename F0, typename... Fs>
void do_in_order(F0&& f0, Fs&&... fs) {
  std::forward<F0>(f0)();
  do_in_order( std::forward<Fs>(fs)... );
}

次のように使用します。

do_in_order( [&]{ some_function(std::forward<Args>(args)); }... );

実行したいアクションを匿名のnullaryフルキャプチャラムダでラップし、 を使用...して上記のラムダのインスタンスのセット全体を作成し、 に渡しますdo_in_order。これは完全な転送を介してそれらを順番に呼び出します。

これは、コンパイラがインライン化して一連の呼び出しに減らすのが簡単なはずです。そして、それが何をするかを直接言い、奇妙な void キャスト、コンマ演算子の使用、または値が破棄される配列を必要としません。

于 2013-04-15T14:38:57.073 に答える