C ++ 11可变参数模板和逗号分隔表达式等价

时间:2013-04-15 09:33:20

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

在可变参数模板中,...运算符将参数包扩展为一系列以逗号分隔的参数(最简单的形式)。我的问题是:为什么调用some_function()为多个参数逗号分隔的作品,并用...运算符调用它?

我在谈论这段代码:

template<typename... Args> inline void expand(Args&&... args) 
{
   some_function(22),some_function(32); // Works
   some_function(args)...; // Doesn't work - ERROR
}

这两行不应该产生类似的输出吗?

3 个答案:

答案 0 :(得分:6)

正如在另一个答案中所说,通过扩展参数包得到的逗号不是逗号oparator,而是参数列表。将参数列表作为表达式显然是一个错误。由于您不需要函数的返回值,您可以尝试以下行:

template <class... T>
void ignore(T&&...) {}

template<typename... Args> inline void expand(Args&&... args) 
{
   ignore(some_function(args)...); 
}

如果some_function返回void,则包扩展将无效,因为您无法为函数提供无效“值”。您可以使用逗号运算符返回值或链接some_function的每个调用:

template<typename... Args> inline void expand(Args&&... args) 
{
   ignore( (some_function(args),true)...); 
   //or:
   bool b[] = {(some_function(args),true)...};
}

答案 1 :(得分:5)

因为在第一种情况下你没有逗号分隔的参数,而是使用逗号运算符,这是一个完全不同的野兽。

您可以递归地实现函数expand

inline void expand() {}

template<typename T, typename... Args>
inline void expand(T&& head, Args&&... tail)
{
    some_function(head);
    expand(tail...);
}

答案 2 :(得分:1)

一个直截了当的答案是,这不是标准允许包扩展的上下文。允许上下文的完整列表在14.5.3 / 4中指定:

  

4包扩展包括一个模式和一个省略号,   其实例化产生零个或多个实例化   列表中的模式(如下所述)。模式的形式取决于   在扩张发生的背景下。包装扩展可以   发生在以下情况中:

     

- 在函数参数包(8.3.5)中;模式是   没有省略号的参数声明。

     

- 在作为包扩展的模板参数包(14.1)中:

     
      
  • 如果模板参数包是参数声明;该   pattern是没有省略号的参数声明;

  •   
  • 如果模板参数包是带有的类型参数   模板参数列表;模式是对应的   没有省略号的type-parameter。

  •   
     

- 在初始化列表中(8.5);模式是初始化子句。

     

- 在基础指定列表中(第10条);该模式是基础规范。

     

- 在mem-initializer-list(12.6.2)中;模式是一个   MEM-初始化。

     

- 在template-argument-list(14.3)中;模式是一个   模板的参数。

     

- 在动态异常规范中(15.4);模式是一个   型-ID。

     

- 在属性列表(7.6.1)中;模式是一个属性。

     

- 在对齐指定器(7.6.2)中;模式是   alignment-speci fi er没有省略号。

     

- 在捕获列表(5.1.2)中;模式是捕获。

     

- 在sizeof ...表达式中(5.3.3);这种模式是一种认同。

这是一种可能的解决方法,可以保证以从左到右的顺序评估参数:

struct expand_aux {
    template<typename... Args> expand_aux(Args&&...) { }
};

template<typename... Args>
inline void expand(Args&&... args)
{
    expand_aux  temp { some_function(std::forward<Args>(args))...  };
}