4

可変個引数テンプレートでは、... 演算子はパラメーター パックを一連のコンマ区切りの引数に (最も単純な形式で) 展開します。私の質問は、コンマで区切られた複数の引数に対して some_function() を呼び出すと機能し、... 演算子で呼び出すと機能しないのはなぜですか?

私はこのコードについて話している:

template<typename... Args> inline void expand(Args&&... args) 
{
   some_function(22),some_function(32); // Works
   some_function(args)...; // Doesn't work - ERROR
}

これらの 2 行は同様の出力を生成するべきではありませんか?

4

3 に答える 3

6

他の回答で述べたように、パラメーター パックを展開して得られるコンマは、コンマ演算子ではなく、引数リストです。引数リストを式として持つことは明らかにエラーです。関数の戻り値は必要ないため、次の行で何かを試すことができます。

template <class... T>
void ignore(T&&...) {}

template<typename... Args> inline void expand(Args&&... args) 
{
   ignore(some_function(args)...); 
}

しかしsome_functionreturnの場合void、関数に void の「値」を与えることができないため、パック展開は機能しません。値を返すかsome_function、コンマ演算子を使用して各呼び出しをチェーンすることができます。

template<typename... Args> inline void expand(Args&&... args) 
{
   ignore( (some_function(args),true)...); 
   //or:
   bool b[] = {(some_function(args),true)...};
}
于 2013-04-15T09:57:17.430 に答える
5

最初のケースでは、コンマ区切りの引数がありませんが、代わりにコンマ演算子を使用しているため、まったく異なる獣です。

関数をexpand再帰的に実装できます。

inline void expand() {}

template<typename T, typename... Args>
inline void expand(T&& head, Args&&... tail)
{
    some_function(head);
    expand(tail...);
}
于 2013-04-15T09:37:28.620 に答える
2

率直な答えは、これは標準がパックの拡張を許可するコンテキストではないということです。許可されたコンテキストの完全なリストは、14.5.3/4 で指定されています。

4 パック展開は、パターンと省略記号で構成され、そのインスタンス化により、リスト内のパターンの 0 個以上のインスタンス化が生成されます (後述)。パターンの形式は、展開が発生するコンテキストによって異なります。パック拡張は、次のコンテキストで発生する可能性があります。

— 関数パラメータパック (8.3.5); パターンは、省略記号のないパラメーター宣言です。

— パック拡張 (14.1) であるテンプレート パラメーター パック:

  • テンプレート パラメーター パックがパラメーター宣言の場合。パターンは、省略記号のないパラメーター宣言です。

  • テンプレート パラメーター パックがテンプレート パラメーター リストを持つ型パラメーターである場合。パターンは、省略記号を除いた対応する型パラメーターです。

— 初期化子リスト (8.5) 内。パターンは初期化句です。

— base-specifier-list (第 10 節); パターンは base-specifier です。

— mem-initializer-list (12.6.2); パターンは mem-initializer です。

— テンプレート引数リスト (14.3)。パターンはテンプレート引数です。

— 動的例外仕様 (15.4)。パターンはタイプ ID です。

— 属性リスト (7.6.1)。パターンは属性です。

— アラインメント指定子 (7.6.2) 内。パターンは、省略記号を除いた配置指定子です。

— キャプチャリスト (5.1.2)。パターンはキャプチャです。

— sizeof... 式 (5.3.3) 内。パターンは識別子です。

引数が左から右の順序で評価されることを保証する 1 つの可能な回避策を次に示します。

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

template<typename... Args>
inline void expand(Args&&... args)
{
    expand_aux  temp { some_function(std::forward<Args>(args))...  };
}
于 2013-04-15T09:52:29.287 に答える