【发布时间】:2020-01-09 00:51:25
【问题描述】:
我想更好地理解参数包扩展,所以我决定研究一下,曾经对我来说很明显的事情,在尝试了解到底发生了什么之后不再那么明显了。让我们用std::forward 来检查一个标准参数包扩展:
template <typename... Ts>
void foo(Ts&& ... ts) {
std::make_tuple(std::forward<Ts>(ts)...);
}
我的理解是,对于任何参数包Ts,std::forward<Ts>(ts)... 将产生一个逗号分隔的转发参数列表及其相应类型,例如,对于ts 等于1, 1.0, '1',函数体将扩展为:
std::make_tuple(std::forward<int&&>(1), std::forward<double&&>(1.0), std::forward<char&&>('1'));
这对我来说很有意义。与函数调用一起使用的参数包扩展会生成一个以逗号分隔的对该函数的调用列表,其中包含适当的参数。
似乎困扰我的是,如果我们想以类似的方式调用一堆函数,为什么有时需要引入逗号运算符 (operator,)?看到this answer,我们可以阅读这段代码:
template<typename T>
static void bar(T t) {}
template<typename... Args>
static void foo2(Args... args) {
(bar(args), ...); // <- notice: comma here
}
int main() {
foo2(1, 2, 3, "3");
return 0;
}
随后的信息表明它将导致以下扩展:
(bar(1), bar(2), bar(3), bar("3"));
公平,有道理,但是……为什么?为什么要这样做:
template<typename... Args>
static void foo2(Args... args) {
(bar(args)...); // <- notice: no comma here
}
不工作?根据我的逻辑(“参数包扩展,与函数调用一起使用,会产生一个以逗号分隔的对该函数的调用列表”),它应该扩展为:
(bar(1), bar(2), bar(3), bar("3"));
是因为bar()返回void吗?好吧,将bar() 更改为:
template<typename T>
static int bar(T t) { return 1; }
没有任何改变。我想它只会扩展到1s 的逗号分隔列表(如果bar() 是这样设计的,可能会产生一些副作用)。为什么这会有不同的表现?我的逻辑哪里有问题?
【问题讨论】:
-
void()不是函数调用,而是强制转换。 -
@0x499602D2 我相信我没有说这是一个函数调用。我用它来编译
void(std::forward<Ts>(ts)...);。后来一直坚持。当我提到函数调用时,我指的是bar()和std::forward()调用。 -
@0x499602D2 "参数包扩展" -
..."用于函数调用" -bar(args)。如果您认为我应该在这里用不同的方式表达,我很乐意借此机会澄清意图并编辑问题。 -
void(std::forward<Ts>(ts)...);does not in fact compile。您要查找的术语是fold expression -
@Fureeish:
(args + ...)在扩展中根本没有逗号。
标签: c++ c++17 variadic-templates