没有typedef的变量扩展器

vso*_*tco 6 c++ templates variadic-templates c++11

通常用于执行可变参数扩展的一个技巧是使用未组合的数组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);
}
Run Code Online (Sandbox Code Playgroud)

Live on Coliru

我们可以在不引入typedef的情况下这样做吗?如果我直接尝试

(void)int[]{0, (std::forward<Ts>(ts)(), 0)...};
Run Code Online (Sandbox Code Playgroud)

gcc/clang吐了出来

错误:'int'之前的预期primary-expression

如果我尝试括号,代码编译但我相信它是非标准的:

警告:ISO C++禁止复合文字[-Wpedantic]

Pra*_*ian 6

在这个表达中

(void)int[]{0, (std::forward<Ts>(ts)(), 0)...};
Run Code Online (Sandbox Code Playgroud)

您正在尝试使用功能表示法转换来创建临时数组.这是行不通的,因为该语言只允许函数表示法与simple-type-specifiertypename-specifier一起使用.

来自[expr.type.conv]/3

类似地,一个简单型说明符类型名称说明符后跟一个支撑-INIT列表创建具有指定的指定类型的直接清单初始化(8.5.4)的一个临时对象支撑-INIT列表,其值是临时对象作为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)()), ...);
}
Run Code Online (Sandbox Code Playgroud)

现场演示


Jar*_*d42 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
}
Run Code Online (Sandbox Code Playgroud)

  • @vsoftco因为负责任的C++程序员使用保护...来防止重载的逗号运算符:) (4认同)
  • @vsoftco是的,您可以转换可调用的返回值,或者您可以执行Jarod所做的操作.`void()`不是函数类型,它是`void`类型的表达式,你不能用'void`重载逗号运算符. (4认同)