Variadic模板包扩展

Variadic模板包扩展

我正在尝试学习可变参数模板和函数。我无法理解为什么这段代码不能编译:

template<typename T>static void bar(T t) {}template<typename... Args>static void foo2(Args... args){
    (bar(args)...);}int main(){
    foo2(1, 2, 3, "3");
    return 0;    }

当我编译它失败时出现错误:

错误C3520:'args':必须在此上下文中扩展参数包

(在功能上foo2)。


潇潇雨雨
浏览 833回答 3
3回答

绝地无双

可以发生包扩展的地方之一是在braced-init-list中。您可以通过将扩展放在虚拟数组的初始化列表中来利用此功能:template<typename... Args>static void foo2(Args &&... args){&nbsp; &nbsp; int dummy[] = { 0, ( (void) bar(std::forward<Args>(args)), 0) ... };}要更详细地解释初始化程序的内容:{ 0, ( (void) bar(std::forward<Args>(args)), 0) ... };&nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp;|&nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp;--- pack expand the whole thing&nbsp;&nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp;&nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp;--perfect forwarding&nbsp; &nbsp; &nbsp;--- comma operator&nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;-- cast to void to ensure that regardless of bar()'s return type&nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; the built-in comma operator is used rather than an overloaded one&nbsp; |&nbsp; ---ensure that the array has at least one element so that we don't try to make an&nbsp; &nbsp; &nbsp;illegal 0-length array when args is empty演示。。扩展的一个重要优势{}是它保证了从左到右的评估。使用C ++ 17&nbsp;折叠表达式,您只需编写即可((void) bar(std::forward<Args>(args)), ...);

达令说

参数包只能在严格定义的上下文列表中进行扩展,而运算符,不是其中之一。换句话说,不可能使用包扩展来生成由运算符分隔的一系列子表达式组成的表达式,。经验法则是“扩展可以生成一个分隔模式列表,,其中,是一个列表分隔符。”&nbsp;运算符,不构造语法意义上的列表。要为每个参数调用一个函数,可以使用递归(这是可变参数模板程序员框中的主要工具):template&nbsp;<typename&nbsp;T>void&nbsp;bar(T&nbsp;t)&nbsp;{}void&nbsp;foo2()&nbsp;{}template&nbsp;<typename&nbsp;Car,&nbsp;typename...&nbsp;Cdr>void&nbsp;foo2(Car&nbsp;car,&nbsp;Cdr...&nbsp;cdr){ &nbsp;&nbsp;bar(car); &nbsp;&nbsp;foo2(cdr...);}int&nbsp;main(){ &nbsp;&nbsp;foo2&nbsp;(1,&nbsp;2,&nbsp;3,&nbsp;"3");}实例

函数式编程

SHAMELESS COPY&nbsp;[来源批准]参数包只能在严格定义的上下文列表中进行扩展,而运算符,不是其中之一。换句话说,不可能使用包扩展来生成由运算符分隔的一系列子表达式组成的表达式,。经验法则是“扩展可以生成一个分隔,模式列表,其中,是一个列表分隔符。”&nbsp;运算符,不构造语法意义上的列表。要为每个参数调用一个函数,可以使用递归(这是可变参数模板程序员框中的主要工具):#include&nbsp;<utility>template<typename&nbsp;T>void&nbsp;foo(T&nbsp;&&t){}template<typename&nbsp;Arg0,&nbsp;typename&nbsp;Arg1,&nbsp;typename&nbsp;...&nbsp;Args>void&nbsp;foo(Arg0&nbsp;&&arg0,&nbsp;Arg1&nbsp;&&arg1,&nbsp;Args&nbsp;&&...&nbsp;args){ &nbsp;&nbsp;&nbsp;&nbsp;foo(std::forward<Arg0>(arg0)); &nbsp;&nbsp;&nbsp;&nbsp;foo(std::forward<Arg1>(arg1),&nbsp;std::forward<Args>(args)...);}auto&nbsp;main()&nbsp;->&nbsp;int{ &nbsp;&nbsp;&nbsp;&nbsp;foo(1,&nbsp;2,&nbsp;3,&nbsp;"3");}有用的非复制信息你可能在这个答案中没有看到的另一件事是使用说明&&符和std::forward。在C ++中,说明&&符可以表示两种内容之一:rvalue-references或通用引用。我不会进入rvalue-references,而是进入使用可变参数模板的人;&nbsp;普遍的参考是神的发送。完美的转发std::forward通用引用的一个用途是将类型转换为其他函数。在你的例子中,如果我们传递int&给foo2它,它会自动降级为int因为foo2模板扣除后生成的函数的签名,如果你想arg将它转发给另一个通过引用修改它的函数,你将得到不希望的结果(变量将不会被更改)因为foo2将传递一个引用传递int给它创建的临时变量。为了解决这个问题,我们指定了一个转发函数来对变量(rvalue&nbsp;或&nbsp;lvalue)进行任何类型的引用。然后,为了确保我们传递了我们使用的转发函数中传递的确切类型,那么只有std::forward那么我们是否允许降级类型;&nbsp;因为我们现在处于最重要的地步。如果您需要,请阅读有关通用引用和完美转发的更多信息&nbsp;;&nbsp;Scott Meyers作为一种资源非常棒。
打开App,查看更多内容
随时随地看视频慕课网APP