用Cpp11新template feature尝试metaprogramming

来源:互联网 发布:淘宝网站的盈利来源 编辑:程序博客网 时间:2024/04/30 13:05

Cplusplus 11 发布大半年了, 基本上浏览了一遍wiki pedia上关于新feature的介绍, 个别feature已经迅速被大家广泛运用了, 剩下的由于编译器的支持问题未敢大肆使用。由于 新标准在core language中就提供了以前要一堆template才能实现的feature以及std lib中把boost的一些container搬字过纸,所以熟悉boost的人可能一看介绍马上就懂得怎么用了。 我自己对template一直比较感兴趣, 所以很自然地对新标准中关于template的改进特别关注,这里介绍一下新标准中的变参模板, 并以此实现一下metaprogramming中的一下戏法。如果你不熟悉metaprogramming, 直接忽略本文可也。。。


关于变参模板的使用方法请参考 http://en.wikipedia.org/wiki/Variadic_templates


好了, 马上开始用新技术实现一些旧戏法(warning: 我没有写详尽的unit test,也未把以下代码用于实战,仅仅是手痒,代码你可以随便用,但是出问题了别找我!)


代码用gcc 4.6测试通过。。。


首先variadic template实现bool变量, 用以后续实现更深的条件语句,改用variadic template的好处就是可以传空模板参数,并不是纯粹为了以新换旧。

struct _error;template<bool...>struct bool_;template<bool Value>struct bool_<Value> {    typedef bool_<Value> type;    static const bool value = Value;//为了可以打印,其实可删除};template<>struct bool_<>: public bool_<0> {};typedef bool_<0> false_;typedef bool_<1> true_;


接着是variadic template实现的编译期整数,好处同上。
typedef uintmax_t pint_t;typedef intmax_t  nint_t;template<pint_t...>struct PInt;template<pint_t value>struct PInt<value> {    typedef PInt<value> type;    static const pint_t v = value;};template<nint_t...>struct NInt;template<nint_t value>struct NInt<value> {    static_assert(value < 0, "NInt value must be < 0.  Otherwise, use PInt.");    typedef NInt<value> type;    static const nint_t v = value;};template<>struct PInt<>: public PInt<0> {};typedef PInt<0> Zero;typedef PInt<1> One;typedef PInt<2> Two;


接着是metaprogramming必须的一些component, 毫不客气地说, boost差不多也是这么实现的了。

template<class TheType>struct identity{typedef TheType type;};template<class A>struct isTrue {    typedef true_ type;};template<>struct isTrue<false_> {    typedef false_ type;};template<>struct isTrue< PInt<0> > {    typedef false_ type;};


接着强势插入编译期条件语句的实现, 没有新东西。。。重复做轮子了, 晕。
template<class Cond, class Then, class Else>struct _ifAux {    typedef typename Then::type type;};template<class Then, class Else>struct _ifAux<false_, Then, Else> {    typedef typename Else::type type;};template<class Cond, class Then, class Else>struct eval_if {    typedef    typename _ifAux<        typename isTrue<Cond>::type,        Then,        Else        >::type    type;};


对, 为了方便测试而写的, 实际绝对不应该这么写的, 看官小心。。。

// not a good solutiontemplate<long i>struct GetInt{    typedef typename eval_if<bool_<(i<0)>, NInt<i>, PInt<i> >::type type;};


无聊的加法。。。
template<class A, class B>struct plus;template<pint_t val1, pint_t val2>struct plus< PInt<val1>, PInt<val2> > {    typedef PInt<(val1 + val2)> type;};template<pint_t val1, nint_t val2>struct plus< PInt<val1>, NInt<val2> > {    typedef    typename eval_if<        bool_<!((val1)<((pint_t)-val2))>,        identity< PInt<(val1 - (pint_t)-val2)> >,        identity< NInt<((nint_t)val1 + val2)> >        >::type    type;};template<nint_t val1, pint_t val2>struct plus< NInt<val1>, PInt<val2> > {    typedef typename plus< PInt<val2>, NInt<val1> >::type type;};


无聊的取反。。。
template<class A>struct negate;template<pint_t val1>struct negate< PInt<val1> > {    typedef NInt<-(nint_t)val1> type;};template<>struct negate< Zero > {    typedef Zero type;};template<nint_t val1>struct negate< NInt<val1> > {    typedef PInt<(pint_t)-val1> type;};


减法和整数工厂方法,由于简单,一次散出。。。
template<class A, class B>struct minus {    typedef    typename plus<A,typename negate<B>::type>::type    type;};template<class A, int>struct spawn;template<pint_t val1, int val2>struct spawn< PInt<val1>, val2 > {    typedef    typename eval_if<        bool_<(val2 < 0)>,        identity< NInt<val2> >,        identity< PInt<val2> >        >::type    type;};template<nint_t val1, int val2>struct spawn< NInt<val1>, val2 > {    typedef    typename eval_if<        bool_<(val2 < 0)>,        identity< NInt<val2> >,        identity< PInt<val2> >        >::type    type;};template<nint_t val1>struct make_int {    typedef    typename eval_if<        bool_<(val1 < 0)>,        identity< NInt<val1> >,        identity< PInt<val1> >        >::type    type;};


好了, 新feature带来的亮点隆重登场, 等很久了吧, 这种类似switch case的编译期作法, 用旧式fix parameter template, 得折腾好一阵了, 用了新式变参模板, 世界顿时美好多了, 不过话说编译期的递归层数是有限的, 看官得小心。。。
template<class, class, class...>struct cond;template<class Cond, class Then, class Else>struct cond<Cond,Then,Else> {    typedef    typename eval_if<typename Cond::type,Then,Else>::type    type;};template<class Cond, class Then, class Cond2, class Then2, class... More>struct cond<Cond,Then,Cond2,Then2,More...> {    typedef    typename eval_if<        typename Cond::type,        Then,        cond<Cond2,Then2,More...>        >::type    type;};


variadic template实现的编译期逻辑运算符, 同样爽吧。。。
template<class... Cond>struct or_;template<>struct or_<> {    typedef false_ type;};template<class First, class... Other>struct or_<First,Other...> {    typedef    typename eval_if<        typename First::type,        identity<true_>,        or_<Other...>        >::type    type;};template<class... Cond>struct and_;template<>struct and_<> {    typedef true_ type;};template<class First, class... Other>struct and_<First,Other...> {    typedef    typename eval_if<        typename First::type,        and_<Other...>,        identity<false_>        >::type    type;};template<class Cond>struct _not {    typedef    typename eval_if<        Cond,        identity<false_>,        identity<true_>        >::type    type;};


compare运算, 旧东西拿来唬人, 你懂的。。。
template<class A, class B> struct less;template<pint_t val1, pint_t val2>struct less< PInt<val1>, PInt<val2> > {    typedef bool_<((val1)<(val2))> type;};template<nint_t val1, nint_t val2>struct less< NInt<val1>, NInt<val2> > {    typedef bool_<((val1)<(val2))> type;};template<nint_t val1, pint_t val2>struct less< NInt<val1>, PInt<val2> > {    typedef true_ type;};template<pint_t val1, nint_t val2>struct less< PInt<val1>, NInt<val2> > {    typedef false_ type;};template<class A, class B>struct less_equal {    typedef    typename _not<typename less<B,A>::type>::type    type;};template<class A, class B>struct greater {    typedef typename less<B,A>::type type;};template<class A, class B>struct greater_equal {    typedef typename less_equal<B,A>::type type;};template<class A, class B>struct equal_to {    typedef    typename and_<less_equal<A,B>,less_equal<B,A> >::type    type;};template<class A, class B>struct not_equal_to {    typedef    typename _not<typename equal_to<A,B>::type>::type    type;};


乘除法来了,乘法好tricky,没有啦,也就递归成加法而已,呵呵。。。
template<class A, class B>struct divides;template<pint_t val1, pint_t val2>struct divides< PInt<val1>, PInt<val2> > {    typedef PInt<(val1 / val2)> type;};template<nint_t val1, nint_t val2>struct divides< NInt<val1>, NInt<val2> > {    typedef PInt<((pint_t)-val1 / (pint_t)-val2)> type;};template<pint_t val1, nint_t val2>struct divides< PInt<val1>, NInt<val2> > {    typedef typename make_int<((nint_t)val1 / val2)>::type type;};template<nint_t val1, pint_t val2>struct divides< NInt<val1>, PInt<val2> > {    typedef typename make_int<(val1 / (nint_t)val2)>::type type;};template<class A>struct recip: public divides<One,A> {};template<class A>struct isOdd {    typedef    typename equal_to<            typename divides<A,Two>::type,            typename divides<typename minus<A,One>::type,Two>::type        >::type    type;};template<class A, class B>struct times {    struct _Expr1 {        typedef        typename negate<typename times<A,typename negate<B>::type>::type>::type        type;    };    struct _Expr2 {        typedef        typename plus<A,typename times<A,typename minus<B,One>::type>::type>::type        type;    };    struct _Expr3 {        typedef        typename times<typename plus<A,A>::type,typename divides<B,Two>::type>::type        type;    };    typedef    typename cond<        equal_to<B,Zero>,  spawn<A,0>,        equal_to<B,One>,   identity<A>,        less<B,Zero>,  _Expr1,        isOdd<B>,    _Expr2,        _Expr3        >::type    type;};


求模。。。
template<class A, class B>struct modulus {    typedef    typename minus<A,typename times<typename divides<A,B>::type,B>::type>::type    type;};template<class T>struct print {    typedef T type;};


到这里直接上演应用了 ,应用中也大量使用variadic template,  编译期求一堆数字的奇偶性。。。 
template<typename... Args>struct list {    typedef list<Args...> type;    typedef tuple<Args...> ttype; // 为了打印    static const std::size_t size = sizeof...(Args); //为了打印};template<std::size_t i, typename TT>struct loop_list{    static void run()    {        cout << std::boolalpha;        cout << std::tuple_element<i, TT>::type::value << endl;        loop_list<i-1, TT>::run();    }};template<typename TT>struct loop_list<0, TT>{    static void run()    {cout << std::tuple_element<0, TT>::type::value << endl;}};template<typename LL>void pl(){    typedef typename LL::ttype TT;    loop_list<LL::size-1, TT>::run();}template<typename,typename>struct cons;template<typename x,typename... y>struct cons<x,list<y...> >{    typedef typename list<x,y...>::type type;};template<typename,typename...>struct map;template<typename f>struct map<f>{    typedef typename list<>::type type;};template<typename car,typename... cdr,typename f>struct map<f,car,cdr...>{    typedef typename cons<typename f::template apply<car>::type,                          typename map<f,cdr...>::type>::type type;};struct M_isOdd {    struct M {        template<typename x>        struct apply {            typedef typename ::not_equal_to<                typename ::modulus<x,::PInt<2> >::type,                ::PInt<0>            >::type type;        };    };    typedef M type;};typedef    ::print<        map<M_isOdd::type,            ::PInt<1>,            ::PInt<2>,            ::PInt<3>,            ::PInt<4>,            ::PInt<5>,            ::PInt<6>,            ::PInt<7>,            ::PInt<8>,            ::PInt<9>        >::type    >::type    M8;int main(){    pl<M8>();    return 0;}

完毕, 以后又机会再深入分享。。。