简体   繁体   English

C++ 中的可变参数模板及其工作原理

[英]Variadic templates in C++ and how they work

So I'm trying to understand how variadic templates work, so I have this code:所以我试图了解可变参数模板是如何工作的,所以我有这个代码:

template <typename Res, typename Type>
void Sum(Res &result, Type &val)
{
    result += val;
}

template <typename Res, typename First, typename... Rest>
void Sum(Res &result, First val1, Rest... valN)
{
    result += val1;
    return Sum(result, valN...);
}

Now my book says that:现在我的书说:

the compiler actually creates code for the right kind of Sum() that would suit the call, doing so recursively until all arguments have been processed.编译器实际上为适合调用的正确类型的Sum()创建代码,递归地执行此操作,直到所有 arguments 都已处理。

Now I don't understand this, I also tried debugging and I saw that the second Sum function block gets called for each valN value, and then at the last one calls the first Sum() function, this doesnt make any sense for me.现在我不明白这一点,我也尝试调试,我看到第二个 Sum function 块被每个 valN 值调用,然后在最后一个调用第一个Sum() function,这对我没有任何意义。

I also learned that to unpack them we need to use function calls inside the variadic template function, is that true?我还了解到,要解压它们,我们需要在可变参数模板 function 中使用 function 调用,这是真的吗?

And why to we have to unpack them, I don't understand, can't we just access them directly in the variadic template function?为什么我们必须解压它们,我不明白,我们不能直接在可变参数模板 function 中访问它们吗?

Thanks in advance.提前致谢。

I think that you might miss the point that when you step through this in the debugger, you're entering a completely different function each time.我认为您可能会错过这一点,即当您在调试器中逐步执行此操作时,您每次都会输入一个完全不同的 function。
(Note that val1 is not used in the "next" call, so you're passing one argument less each time.) (请注意,“下一个”调用中不使用val1 ,因此您每次都少传递一个参数。)

If there weren't variadic templates, you would need to spell these out as separate templates, but it would be exactly the same:如果没有可变参数模板,您需要将它们拼写为单独的模板,但它是完全相同的:

template <typename Res, typename T>
void Sum(Res& result, T val)
{
    result += val;
}

template <typename Res, typename T1, typename T2>
void Sum(Res& result, T1 val1, T2 val2)
{
    result += val1;
    Sum(result, val2);
}

template <typename Res, typename T1, typename T2, typename T3>    
void Sum(Res& result, T1 val1, T2 val2, T3 val3)
{
    result += val1;
    Sum(result, val2, val3);
}

template <typename Res, typename T1, typename T2, typename T3, typename T4>        
void Sum(Res& result, T1 val1, T2 val2, T3 val3, T4 val4)
{
    result += val1;
    Sum(result, val2, val3, val4);
}

template <typename Res, typename T1, typename T2, typename T3, typename T5>    
void Sum(Res& result, T1 val1, T2 val2, T3 val3, T4 val4, T5 val5)
{
    ...

and so on, as many of them as you need.等等,你需要多少就多少。

The variadic template makes the compiler generate all of these "on demand" and saves you from writing them all out.可变参数模板使编译器“按需”生成所有这些,并避免您将它们全部写出来。

One way to look at it is that regular function templates (with only type parameters) generate overloads with the same number of parameters;一种看待它的方法是,常规的 function 模板(只有类型参数)生成具有相同数量参数的重载; variadic templates let you also generate overloads with varying amounts of parameters.可变参数模板还允许您生成具有不同数量参数的重载。

Direct access is impossible because you don't know how many elements there inside the parameter pack, what their types are, and they don't have names.直接访问是不可能的,因为您不知道参数包中有多少元素,它们的类型是什么,并且它们没有名称。
If you want to access a specific argument you also need to make it explicit.如果你想访问一个特定的参数,你还需要让它显式。

Just imagine that templates work as if there is a function created every time you match one of the template specifications.试想一下,模板的工作方式就像每次匹配其中一个模板规范时都会创建一个 function。

  • If you have 4 arguments, the compiler sees that that matches the parameter pack definition, which is calls to the 3 argument version.如果您有 4 个 arguments,编译器会看到与参数包定义匹配,即对 3 个参数版本的调用。
  • Then that version needs to be generated as well, but that again calls to the 2 argument version.然后也需要生成该版本,但这再次调用 2 参数版本。
  • That one does not match the second definition, but the first, which can be fully resolved.那个不符合第二个定义,而是第一个,完全可以解决。

Function calls are not strictly necessary for unpacking, see Expansions section on cppreference . Function 调用并不是解包所必需的,请参阅cppreference 上的扩展部分

Direct access is not possible, because it implies that the parameter pack is not variadic.直接访问是不可能的,因为这意味着参数包不是可变参数。 However, you can always write your version of function directly referring to the template of any index by just providing a template integerand expanding the parameter pack while decrementing the integer (and have a special behaviour defined when it is 0).但是,您始终可以编写您的 function 版本,直接引用任何索引的模板,只需提供一个模板整数并在递减 integer 时扩展参数包(并在其为 0 时定义特殊行为)。

[Example for printing out a partial sum on the fifth processed argument of the variadic template] [在可变参数模板的第五个处理参数上打印部分和的示例]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM