web-dev-qa-db-ja.com

「...」で拡張されていないパラメータパック

私はこのコードを持っています:

_#include <iostream>
using namespace std;

int print(int i)
{
    cout << endl << i;
}

template<typename ...Args>
inline void pass(Args&&...args)
{

}

template<typename ...args>
inline void expand(args&&... a)
{
    print(a) ...; //this doesn't expand
    //pass( print(a)... ); this works
}

int main() {
    expand(1,2,3,4);
    return 0;
}
_

エラーをスローします:

_ In function 'void expand(args&& ...)':
error: expected ';' before '...' token
  print(a) ...;
           ^
parameter packs not expanded with '...':
  print(a) ...;
              ^
_

pass()関数の使用が必要なのはなぜですか?

13
q126y

基本的に、パラメータパック_E..._を展開すると、list_E1, E2, [...], EN_が生成され、1つのEがパック。この構文構成は、リストが文法的に正しい場所(関数呼び出し、初期化リストなど)でのみ有効です。複数のコンマ演算子を含む式はカウントされません。

折りたたみ式N4295:折りたたみ式(アンドリューサットン、リチャードスミス) )を使用すると、次のように簡単に記述できると思います。

_(print(a), ...);
_

この表現では、

  • print(a)は、展開されていないパラメーターパックを含む式です。
  • _,_は演算子であり、
  • _..._は、右折りたたみ展開を指定します。

式全体の結果は、_(print(a), ...)_が次のように変換されることです。

_print(a1) , (print(a2), (print(a3), print(a4))) // (assuming four elements). 
_
17
TartanLlama

パック展開は、パック展開コンテキストでのみ発生します。これらは基本的に次のとおりです。

  • ブレース初期化
  • 初期化リスト
  • 集計初期化
  • 関数呼び出し
  • 配列の初期化

これらのうち、あなたのケースで使いやすいのが最後です:

#include <iostream>
using namespace std;
int print(int i)
{
    cout<<endl<<i;
    return 0;
}

template<typename ...args>
inline void expand(args&&... a)
{
    using expander = int[]; 
    (void)expander{0, ((void)print(a), 0)...}; 
}

int main() 
{
    expand(1,2,3,4);

    return 0;
}

Demo

6

これも機能します:

#include <iostream>

void print() {}

template<typename T, typename ... Types>
void print (T firstArg, Types ... args) {
    std::cout << firstArg << "\n";
    print(args...);
}

int main() {
    print("Hello",1337,42.44,"World");
}

Demo

1
cosurgi