C++17 フォールド式
(f(args), ...);
オーバーロードされたコンマ演算子を使用してオブジェクトを返す可能性のあるものを呼び出す場合:
((void)f(args), ...);
C++17 より前のソリューション
ここでの典型的なアプローチは、ダムリスト初期化子を使用し、その中で展開を行うことです:
{ print(Args)... }
カーリー初期化子では、評価の順序は左から右に保証されます。
しかし、print
戻ってくるvoid
ので、それを回避する必要があります。それではintにしましょう。
{ (print(Args), 0)... }
ただし、これはステートメントとして直接機能しません。タイプを与える必要があります。
using expand_type = int[];
expand_type{ (print(Args), 0)... };
Args
これは、パック内に常に 1 つの要素がある限り機能します。サイズがゼロの配列は有効ではありませんが、常に少なくとも 1 つの要素を持つようにすることで回避できます。
expand_type{ 0, (print(Args), 0)... };
このパターンをマクロで再利用可能にすることができます。
namespace so {
using expand_type = int[];
}
#define SO_EXPAND_SIDE_EFFECTS(PATTERN) ::so::expand_type{ 0, ((PATTERN), 0)... }
// usage
SO_EXPAND_SIDE_EFFECTS(print(Args));
ただし、これを再利用可能にするには、いくつかの詳細にもう少し注意を払う必要があります。ここではオーバーロードされたカンマ演算子を使用したくありません。いずれかの引数でコンマをオーバーロードできないvoid
ため、それを利用しましょう。
#define SO_EXPAND_SIDE_EFFECTS(PATTERN) \
::so::expand_type{ 0, ((PATTERN), void(), 0)... }
ゼロの大きな配列を無駄に割り当てるコンパイラを恐れている場合は、そのようにリスト初期化できるが何も格納しない他の型を使用できます。
namespace so {
struct expand_type {
template <typename... T>
expand_type(T&&...) {}
};
}