没有typedef

时间:2016-02-05 21:13:44

标签: c++ templates c++11 variadic-templates

通常用于执行可变参数扩展的一个技巧是将未大小的数组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);
}

Live on Coliru

我们可以在不引入typedef的情况下执行此操作吗?如果我直接尝试

(void)int[]{0, (std::forward<Ts>(ts)(), 0)...};

gcc / clang吐出

  

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

如果我尝试使用括号,代码会编译,但我认为它符合非标准:

  

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

4 个答案:

答案 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 一起使用。

来自[expr.type.conv]/3

  

同样,简单类型说明符 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)()), ...);
}

Live demo

答案 2 :(得分:3)

在C ++ 17中,你可以用折叠作为:

template<typename... Ts>
void expander(Ts&&... ts) {
    (..., std::forward<Ts>(ts)());
}

Live Demo

答案 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();
}

https://ideone.com/BzNXhD