在可变参数模板中,...运算符将参数包扩展为一系列以逗号分隔的参数(最简单的形式)。我的问题是:为什么调用some_function()为多个参数逗号分隔的作品,并用...运算符调用它?
我在谈论这段代码:
template<typename... Args> inline void expand(Args&&... args)
{
some_function(22),some_function(32); // Works
some_function(args)...; // Doesn't work - ERROR
}
这两行不应该产生类似的输出吗?
答案 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))... };
}