用Cpp11新template feature尝试metaprogramming

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 solution
template<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;
}

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


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值