Variadic模板包扩展

Variadic Templates pack expansions

本文关键字:扩展 包扩展 Variadic      更新时间:2023-10-16

在Andrei关于GoingNative 2012的演讲中,他谈到了Variadic Templates,并通过下面的例子解释了参数包展开的工作原理。作为这个主题的新手,我发现很难理解每种情况是如何工作的,有人能解释一下扩展是如何在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)...中,列表TsUsVs(在锁定步骤中枚举)的每个成员都将被替换到该模式中,并且将形成逗号分隔的列表:

   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已经扩展了——所以它将通过将v1v2等替换为vs来扩展为A<T1, T2, …, Tn>::fun(v1), A<T1, T2, …, Tn>::fun(v2), …, A<T1, T2, …, Tn>::fun(vm)

KennyTM的答案是完美的。我只是也喜欢样品。但由于他的答案是抽象的,我觉得在他的答案中添加演示是不正确的。所以他的答案演示在这里。我想他的答案是对的,我自己什么都不知道。(如果你支持这个,也支持他的)

显然,这都是psudocode,只是显示扩展状态。

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