使用可变参数lambda迭代可变参数函数模板的参数

Con*_*tor 7 c++ lambda templates variadic-functions c++11

假设我们有以下函数模板:

template <typename Functor, typename... Arguments>
void IterateThrough(Functor functor, Arguments&&... arguments)
{
    // apply functor to all arguments
}
Run Code Online (Sandbox Code Playgroud)

此功能通常如下实现:

template <typename Functor, typename... Arguments>
void IterateThrough1(Functor functor, Arguments&&... arguments)
{
    int iterate[]{0, (functor(std::forward<Arguments>(arguments)), void(), 0)...};
    static_cast<void>(iterate);
}
Run Code Online (Sandbox Code Playgroud)

其他方式:

struct Iterate
{
    template <typename... Arguments>
    Iterate(Arguments&&... arguments)
    {
    }
};

template <typename Functor, typename... Arguments>
void IterateThrough2(Functor functor, Arguments&&... arguments)
{
    Iterate{(functor(std::forward<Arguments>(arguments)), void(), 0)...};
}
Run Code Online (Sandbox Code Playgroud)

我找到了另一种使用可变参数lambda的方法:

template <typename Functor, typename... Arguments>
void IterateThrough3(Functor functor, Arguments&&... arguments)
{
    [](...){}((functor(std::forward<Arguments>(arguments)), void(), 0)...);
}
Run Code Online (Sandbox Code Playgroud)

与前两个相比,这种方法有哪些优点和缺点?

Sim*_*ple 4

呼叫functor现在没有顺序。编译器可以functor按照它想要的任何顺序调用您的扩展参数。举个例子,IterateThrough3(functor, 1, 2)可以做functor(1); functor(2);或它可以做functor(2); functor(1);,而其他两个总是做functor(1); functor(2);

\n\n

标准第 8.5.4/4 节要求{}初始化器内的任何表达式都是从左到右计算的。

\n\n
\n

在花括号初始化列表的初始值设定项列表中,初始值设定项子句(包括任何由 pack\n 扩展 (14.5.3) 生成的子句)按照它们出现的顺序进行计算。

\n
\n\n

第 5.2.2/4 节指出函数调用的参数可以按任何顺序求值。

\n\n
\n

当调用函数时,每个形参 (8.3.5) 应使用其相应的参数进行初始化 (8.5, 12.8, 12.1)。[注意:此类初始化彼此之间的顺序不确定 (1.9) \xe2\x80\x94\n 尾注]

\n
\n\n

这可能不包括求值顺序的措辞(我找不到 ATM),但众所周知,函数的参数是按未指定的顺序求值的。编辑:请参阅@dyp 的评论以获取相关标准引用。

\n

  • @Simple *“这可能不包括求值顺序的措辞”*可能由 1.9/15 涵盖“除非另有说明,单个运算符的操作数和单个表达式的子表达式的求值是不排序的。” 规范性文本,但相当不具体 (2认同)