通常用于执行可变参数扩展的一个技巧是将未大小的数组typedef与逗号运算符结合使用,如下所示:
#include <iostream>
template<typename... Ts>
void expander(Ts&&... ts)
{
using expand = int[];
(void)expand{0, (std::forward<Ts>(ts)(), 0)...};
}
void f()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
int main()
{
expander(f, f);
}
我们可以在不引入typedef的情况下执行此操作吗?如果我直接尝试
(void)int[]{0, (std::forward<Ts>(ts)(), 0)...};
gcc / clang吐出
错误:在'int'之前预期的primary-expression
如果我尝试使用括号,代码会编译,但我认为它符合非标准:
警告:ISO C ++禁止复合文字[-Wpedantic]
答案 0 :(得分:5)
我们可以在不引入typedef的情况下执行此操作吗?
没有typedef,但有一个变量
template<typename... Ts>
void expander(Ts&&... ts)
{
int dummy[] = {0, (std::forward<Ts>(ts)(), void(), 0)...};
static_cast<void>(dummy); // Avoid warning for unused variable
}
答案 1 :(得分:5)
在此表达式中
(void)int[]{0, (std::forward<Ts>(ts)(), 0)...};
您正在尝试使用功能表示法转换来创建临时数组。这不起作用,因为该语言只允许函数表示法与简单类型说明符或 typename-specifier 一起使用。
同样,简单类型说明符或 typename-specifier 后跟 braced-init-list 会创建一个临时对象使用指定的 braced-init-list 指定类型direct-list-initialized(8.5.4),其值为临时对象作为prvalue。
如果您在[dcl.type.simple]下查找 simple-type-specifier 的定义,它不包含任何带数组括号的内容。事实上,它甚至不包含任何超过一个单词的内容。这就是为什么写int(1)
有效,但signed int(1)
不是。
因此,使用C ++ 11/14,您需要typedef
或声明一个数组变量。但是,使用C ++ 1z编译器,您可以使用折叠表达式并避免两者
template<typename... Ts>
void expander(Ts&&... ts)
{
(void(std::forward<Ts>(ts)()), ...);
}
答案 2 :(得分:3)
在C ++ 17中,你可以用折叠作为:
template<typename... Ts>
void expander(Ts&&... ts) {
(..., std::forward<Ts>(ts)());
}
答案 3 :(得分:2)
您可以按照以下方式执行此操作:
#include <iostream>
template<typename... Ts>
void expander(Ts&&... ts)
{
int dummy[sizeof...(Ts)] = {(std::forward<Ts>(ts)(), 0)...};
}
void f()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
int main()
{
expander(f, f, f);
expander();
}