未使用“...”扩展的参数包
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;
}
这个也有效:
#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");
}
加上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)...};
}
我有这个代码:
#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;
}
这个也有效:
#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");
}
加上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)...};
}