template <bool flag> structboolean { using tag = boolean_tag; staticconstbool value = flag; };
template <int64_t N, int64_t D = 1> struct number { using tag = number_tag; staticconstint64_t numer = impl::rat_reduce<(N == 0 || D == 0), N, D>::numer; staticconstint64_t denom = impl::rat_reduce<(N == 0 || D == 0), N, D>::denom; };
这里 tag 就是类型标识。每个类型都有了 tag,就可以编写判断函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
template <typename T> using is_null = boolean<T::tag::is_null>;
template <typename T> using is_pair = boolean<T::tag::is_pair>;
template <typename T> using is_number = boolean<T::tag::is_number>;
template <typename T> using is_boolean = boolean<T::tag::is_boolean>;
template <typename T> using is_symbol = boolean<T::tag::is_symbol>;
流程控制
顺序
顺序是是简单的,一个个写下去就行。比如
1 2 3 4 5
using lst0 = list<number<1>, number<2>, number<3>>; using lst1 = cons<number<1>, cons<number<2>, cons<number<3>, null>>>;
上面我们定义了 list, 但还不能操作
list。现在我们已经有了分支和递归,可以编写一些函数。其中
length计算 list 的长度,list_ref
用于访问元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
template <typename items> structlength { using type = typename if_else<is_null<items>, number<0>, add<number<1>, length<cdr<items>>>>::type; using tag = typename type::tag; };
template <typename items, typename n> structlist_ref { using type = typename if_else<is_equal<n, number<0>>, car<items>, list_ref<cdr<items>, sub<n, number<1>>>>::type; using tag = typename type::tag; };
上面的定义看起来很复杂的样子。但上面的模板代码,完全等价于下面的
Scheme 代码
1 2 3 4 5 6 7 8 9
(define (list-ref items n) (if (= n 0) (car items) (list-ref (cdr items) (- n 1))))
我们统一用 T::type 来获取返回结果。T::tag
获取返回类型。为了达到这种统一,在所有的类型中,都定义 type
和 tag 这两个字段。
特别地,在基础类型中,也添加 type 字段。于是基础类型,就演变成
1 2 3 4 5 6 7 8 9 10 11 12 13 14
template <int64_t N, int64_t D = 1> struct number { using type = number<N, D>; using tag = number_tag; staticconstint64_t numer = impl::rat_reduce<(N == 0 || D == 0), N, D>::numer; staticconstint64_t denom = impl::rat_reduce<(N == 0 || D == 0), N, D>::denom; };
template <bool flag> structboolean { using tag = boolean_tag; using type = boolean<flag>; staticconstbool value = flag; };