Understanding variadic templates
GP and Templates(泛型编程与模板) 现实中许多问题错综而复杂,解决起来极为不易。 人们发现可以将这些问题拆解成更小的问题来进行解决。往往当把问题拆解到最小模块的时候,便能对问题产生新的理解。 能解决问题的根本在于:问题整体可分解为部分,部分可组成为整体,整体等于部分之和。这是还原论的思想,在编程世界叫作分治策略,实现手法分为迭代和递归。 向下拆分,向上总结,就能把一个大问题化为许多小问题,通过解决一个个小问题,最终就能解决整个大问题。 解决之时,需要描述问题的数据和关系。 在C++中,用面向对象来表示事物的整体结构,用数据结构来表示数据之间的关系,用算法来表示具体的逻辑实现。 数据有类型之分,而不同的问题可能本质上实为同类问题,这便导致每次遇到同类问题,还得提供不同类型版本的解法。 因此数据和方法应该进行分离,对数据进行更高层次的抽象。 面向对象编程的目的是将数据和方法关联起来,而为了分离数据和方法之间的依赖,出现了泛型编程。 泛型编程本质上就是对数据类型的高度抽象,使同一个方法能作用到不同的类型,为同类问题提供了一个通解。 C++泛型编程所提供的支持组件便是模板,而Variadic Templates(可变参数模板/可变模板参数),顾名思义,就是支持任意个数、任意类型的模板。 对于一类问题,若发现变化的永远是输入,而解决方法始终不变,便可以使用可变参数模板定义通解。 这个通解,就是问题的「最小模块」,通过迭代或递归,分多次解决分解后的小问题,最终就能解决整个问题。 然而迭代需要持有一个迭代器并改变它,直到某个条件符合。泛型编程发生于编译期,编译期中的整数计算(如enum)或是typedef(using)的类型定义之后就无法进行改变。所以迭代虽然比递归表示起来更加自然,却无法进行实现。 递归符合一切编译期编程的要求,所以可变参数模板由其实现。 由于递归本身的特性,再结合可变参数模板,使得理解起来极为不易。因为你无法看到实际的结果,对于无法看到的东西,理解起来总是比较困难的。 Ellipsis operator and Parameter pack(省略操作符与参数包) 先来看一个简单的可变参数模板示例: template <class… Args> void func(Args… args) { std::cout << sizeof…(args) << std::endl; } … 叫做省略操作符(ellipsis operator),用以表示任意个参数,带省略号的参数称为参数包(Parameter pack)。 当省略操作符出现在参数名(args)左边时,标示着参数是一个参数包;出现在参数名右边时,用于扩展参数包。因为我们无法直接获取参数包 args 中的每个参数,所以只能通过展开的方式来获取,那么如何展开参数包就成了难点所在。 现在 func 函数可以接受任意个参数: func<>… Continue Reading Understanding variadic templates