可以应用这个技巧,改变参数个数逐一减少,实现递归

1)template模板代表的有函数模板和成员模板;variadic是参数,参数数量和参数类型;
(2)新的关键字就是…,template

(1)调用自己,并设置终止条件;隐藏条件是需要cout可以识别;模板时半成品,具体还要看实现;
(2)如果想要知道…args参数数量,就可以使用sizeof…(args);
(3)右侧,3可以与1并存吗,答案是可以并存的,谁更特化就调用谁,1更特化,会调用1;那么3就一直不会被调用;


(1)复习:initial_list实际上是{}统一初始化的底层实现,而initial_list
本身是一个array的指针作为data,接收任意数量的参数,要求参数的类型一致,构造函数会自动将元素搬移到{}的调用容器,完成初始化;
(2)编译器看到{}就会自动形成一个initial_list对象;
(3)此处借用了initial_list完成实现;

这里是利用了标准库中的max,其实max现在也可以接收多个参数(类型一致),通过initial_list实现;

(1)使用非一般的方式处理first和last元素时,例如右侧黑色输出,第一个和最后一个[7.5,最后一个42],这个时候用到类模板,之前例子都是函数模板;
(2)而且需要知道元素个数才可以区分第一个和最后一个,因此用到了sizeof…()来获取args的参数个数;
(3)同时用到元组tuple是一个可以接收任意数量任意类型的东西,称为元组;
(4)从右侧开始,希望cout<<解析make_tuple,因此需要重载cout<<运算符;
(5)get(t)是tuple提供的接口用来取元素;丢给os进行输出;
(6)调用类PRINT_TUPLE<>的print函数,print函数自己调用自己,直至MAX调用2创建特化类中的print()结束;print函数中调用了tuple的接口函数get(t)来取出元素并传给os进行输出;

(1)类模板,才有继承关系;
(2)在进入tuple之后,首先第一个参数被用来作为data变量存储,然后继承另外的那一包tuple;
(3)子类的对象有一个父类的成分;
(4)typename Head::type是成员函数head()的返回类型;为了让编译器认识,只要出现::前面就加上typename;
(5)调用this()返回尾部一包,本来this指的是三格整体,但是会转为那个灰色框起来的部分,进行返回;
(6)注意在初始化的时候,inherited(vtail…)不是创建临时对象,而是赋值给继承的父类,会调用父类的构造函数;

(1)Head无法回答Head::type问题;
(2)改进decltype;如下;

(3)直接加decltype(m_head)是不可以的,因为编译器此时还没有看到m_head;借助lambda的语法形式,将decltype写在右边,就是
auto head()->decltypr(m_head);并且将data放在前面;
(4)后来发现更直接的返回,直接写Head!


注意,此处composited& tail(){return m_tail};要返回引用;如果不是引用,是拷贝值,改变值的时候是改变的拷贝值,出现问题。取值不影响,设值有影响