模板元编程

前一篇文章中介绍了使用lambda calculus构造自然数以及相关运算。在所有的图灵完备的语言中,我们都可以进行类似的行为。之前学习C++的时候,看过一些模板元编程的内容,所以决定用C++重写一遍,作为练习。

说明

模板元编程同样是图灵完备的,例如我们可以用如下的方式构建一个函数

template<typename x>
struct func{
    using ret=x;
 };

尖括号中的x即为输入,func<x>::ret就是我们的返回,不过这里都是类型。在后面我们可以看到非类型的输入和返回。
然而本人才疏学浅,并未找到像lambda演算中返回高阶函数的对应C++代码,所以只能换一种方式。
以下是我们定义0,1,2:

struct zero{
};
template<typename Nat>
struct succ{};  //后继
using one=succ<zero>;
using two=succ<one>;    //succ<succ<zero>>

接下来是加。

template<typename m,typename n>
struct plus;
template<typename Nat0,typename Nat2>
struct plus<succ<Nat0>,Nat2>{
    using ret=typename plus<Nat0,succ<Nat2>>::ret;
};
template<typename Nat>
struct plus<zero,Nat>{
    using ret=Nat;
};

是的,你没有看错其实就是模式匹配。当然这里我们用到的技术叫做模板偏特化SFINAE。等价Haskell代码如下:

plus :: Nat -> Nat -> Nat
plus zero n = n
plus (succ m) n = plus m (n+1)

emplate<typename m,typename n>
struct minus;
template<typename Nat1,typename Nat2>
struct minus<succ<Nat1>,succ<Nat2>>{
    using ret=typename minus<Nat1,Nat2>::ret;
};
template<typename Nat>
struct plus<Nat,zero>{
    using ret=Nat;
};

乘法

template<typename m,typename n>
struct multi;
template<typename Nat0,typename Nat2>
struct multi<succ<Nat0>,Nat2>{
    using ret=typename plus<typename multi<Nat0,Nat2>::ret,Nat2>::ret;
};
template<typename Nat>
struct multi<zero,Nat>{
    using ret=Nat;
};

乘方。

template<typename m,typename n>
struct exp;
template<typename Nat0,typename Nat2>
struct exp<Nat0,succ<Nat2>>{
    using ret=typename multi<typename exp<Nat0,Nat2>::ret,Nat2>::ret;
};
template<typename Nat>
struct exp<Nat,zero>{
    using ret=Nat;
};

更多

之前提到模板参数可以不是类型,例如最经典的阶乘

template<int x>
struct fact
{
    static const int ret=fact<x-1>::ret*(x-1);
};
template<0>
struct fact
{
    static const int ret =1;
};
int x=fib<5>;   //x=120

关于模板元编程还有许多内容,像构造ifwhile之类的在看了上面的例子之后想必也是手到擒来。等到下次我找到什么新的有意思的内容再来补充。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容