C++11 模板元编程 - 模板递归


模板可以被递归调用,在模板递归的过程中,可以执行前面我们提到的两种编译期计算:数值计算和类型计算。

下面我们用模板递归来做数值计算,在编译期计算N的阶乘。

template
struct Factorial
{
    enum { Value = N * Factorial::Value };
};

template<>
struct Factorial<1>
{
    enum { Value = 1 };
};

可以看到,我们在主模板template struct Factorial的定义中,使用了模板自身Factorial::Value。编译器会一直用不同的N - 1的值来具现化主模板,一直到N变为1,这时选择Factorial的特化版本template<> struct Factorial<1>,内部的Value变为1,递归终止了。

我们可以在编译期运行这个函数__print(Factorial<5>::Value),可以看到编译器会打印出120。

对于上面的例子,我们看到是通过模板特化来终止递归的。事实上我们对比一下Haskell语言中计算阶乘的函数实现:

factorial :: Int -> Int
factorial n = n * factorial (n - 1)
factorial 1 = 1

Haskell是一门纯函数式语言,它通过模式匹配进行条件选择,通过递归来进行循环控制。对于上面的factorial定义,当入参是1的时候模式匹配会选择到factorial 1 = 1实现,否则匹配到factorial n = n * factorial (n - 1)的递归实现。

可以看到上面我们使用C++模板的方式和Haskell中定义函数是如此的类似。编译器对模板的特化版本选择就相当是Haskell在做模式匹配,而两者的循环控制都是通过递归来完成。已经证明模板的这种编译时计算能力就是一种纯函数式编程范式,是图灵完备的!

不同的是,C++这种编译期计算支持的计算对象只能是整形常量和类型。

C++这种编译期函数式计算就是本文要介绍的C++模板元编程,类模板在里面充当了函数的角色。本文用到的关于类模板所有知识基本就是前文所述这些。后面我们将会对类模板进行规范化,让其能够和函数式计算更加地一致,最大程度发挥编译期函数式计算的威力。


关于模板的基本知识就介绍这里,我们接下来正式介绍所谓的“模板元编程”!

模板元编程

返回 C++11模板元编程 - 目录

你可能感兴趣的:(C++11 模板元编程 - 模板递归)