c++ 11可变模板和逗号分隔表达式的等价性

C++11 variadic templates and comma-separated expressions equivalence

本文关键字:表达式 分隔 c++      更新时间:2023-10-16

在可变变量模板中…操作符将参数包展开为一系列以逗号分隔的参数(以最简单的形式)。我的问题是:为什么调用some_function()为多个参数逗号分隔工作,并调用它与…运营商不?

我说的是这段代码:

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

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

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

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)...};
}

因为在第一种情况下,您没有逗号分隔的参数,而是使用逗号操作符,这是完全不同的东西。

你可以递归地实现expand函数:

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

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

中指定

4一个包展开由一个图案和一个省略号组成类的实例化产生零个或多个实例化列表中的模式(如下所述)。模式的形式取决于关于扩展发生的上下文。包扩展可以出现在以下上下文中:

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

-在模板参数pack中,它是一个包扩展(14.1):

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

  • 如果模板参数包是带template-parameter-list;模式是相应的

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

-在基本说明符列表中(条款10);模式是一个基本说明符。

-在mem-initializer-list中(12.6.2);模式是mem-initializer .

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

-在动态异常规范中(15.4);模式是id类型。

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

-在对齐说明符(7.6.2)中;模式是不带省略号的对齐说明符。

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

-尺寸为…表达式(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))...  };
}