未使用“...”扩展的参数包

Parameter packs not expanded with '...'

我有这个代码:

#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() 功能?

本质上,扩展参数包 E... 会为包中的每个元素生成一个 list E1, E2, [...], EN,一个 E。此句法构造仅在列表语法正确的地方有效,例如函数调用、初始化列表等。包含多个逗号运算符的表达式不算数。

我相信使用 fold expressions (N4295: Folding expressions (Andrew Sutton, Richard Smith)) 你可以简单地写:

(print(a), ...);

在这个表达式中,

  • print(a)是一个带有未扩展参数包的表达式,
  • , 是运算符,
  • ... 指定右折叠展开。

整个表达式的结果就是(print(a), ...)会被转化为

print(a1) , (print(a2), (print(a3), print(a4))) // (assuming four elements). 

包扩展只能发生在包扩展上下文中。这些基本上是:

  • 支撑初始化
  • 初始化器列表
  • 聚合初始化
  • 函数调用
  • 数组初始化

在您的案例中,最容易使用的是最后一个:

#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

这个也有效:

#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

加上C++17和折叠表达式,上面的代码可以简化如下:

#include <iostream>

template<typename ...args>
inline void print(args&&... a) {
    ((std::cout << a << std::endl), ...);
}

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

您可能需要考虑以下 C++ 11 代码:

#include <iostream>

template<typename T, typename... Ts>
auto printf3(T value, Ts... args) {
    std::cout << value << std::endl;
    (void) std::initializer_list<T>{([&args] {
        std::cout << args << std::endl;
    }(), value)...};
}