在 Andrei 在 GoingNative 2012 上的演讲中,他谈到了可变参数模板,并一度通过下面的示例解释了参数包扩展的工作原理。作为这个主题的新手,我发现很难理解每种情况的工作原理,有人可以解释一下扩展在
gun
的每个函数调用中是如何工作的吗?
template<class... Ts> void fun(Ts... vs) {
gun(A<Ts...>::hun(vs)...);
gun(A<Ts...>::hun(vs...));
gun(A<Ts>::hun(vs)...);
}
1.
gun(A<Ts...>::hun(vs)...)
=> gun(A<T1, T2, …, Tn>::hun(vs)...)
=> gun(A<T1, T2, …, Tn>::hun(v1),
A<T1, T2, …, Tn>::hun(v2),
…,
A<T1, T2, …, Tn>::hun(vm))
2.
gun(A<Ts...>::hun(vs...))
=> gun(A<T1, T2, …, Tn>::hun(vs...))
=> gun(A<T1, T2, …, Tn>::hun(v1, v2, …, vm))
这应该是显而易见的。
3.
gun(A<Ts>::hun(vs)...)
=> gun(A<T1>::hun(v1), A<T2>::hun(v2), …, A<Tn>::hun(vn))
(在这种情况下,如果Ts和vs的长度不同,程序将无法编译)
...
将扩展其前面的模式(包括任何参数包),这意味着,在foo(Ts, Us, Vs)...
中,列表中的每个成员Ts
、Us
、Vs
(在锁定步骤中枚举)将替换为该模式,将形成一个逗号分隔的列表:
foo(Ts, Us, Vs)...
=> foo(T1, U1, V1), foo(T2, U2, V2), …, foo(Tn, Un, Vn)
如果存在嵌套扩展,最里面的模式将首先被扩展。因此,在情况 1 中,模式
Ts
将首先扩展为 T1, T2, …, Tn
。然后,外部 ...
之前的模式是 A<T1, T2, …, Tn>::fun(vs)
— 请注意,Ts
已被扩展 — 因此,通过将 A<T1, T2, …, Tn>::fun(v1), A<T1, T2, …, Tn>::fun(v2), …, A<T1, T2, …, Tn>::fun(vm)
、v1
等替换为 v2
,它将扩展为 vs
。 .
KennyTM的回答很完美。我也喜欢样品。但由于他的答案很抽象,我不认为在他的答案中添加演示是正确的事情。所以他的答案的演示就在这里。我假设他的答案是正确的,我自己一无所知。 (如果你支持这个,也支持他)
显然这都是伪代码,只是显示扩展状态。
void foo<void*,int,char,std::string>(nullptr, 32, '7', "BANANA") {
//gun(A<Ts...>::hun(vs)...);
gun(A<void*,int,char,std::string>::hun(nullptr)
,A<void*,int,char,std::string>::hun(32)
,A<void*,int,char,std::string>::hun('7')
,A<void*,int,char,std::string>::hun("BANANA")
);
//gun(A<Ts...>::hun(vs...));
gun(A<void*,int,char,std::string>::hun(nullptr, 32, '7', "BANANA");
//gun(A<Ts>::hun(vs)...);
gun(A<void*>::hun(nullptr)
,A<int>::hun(32),
,A<char>::hun('7'),
,A<std::string>::hun("BANANA")
);
}