文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>写C++就像练九阴白骨爪

写C++就像练九阴白骨爪

时间:2010-08-21  来源:gogozhaoxinfeng

写C++就像练九阴白骨爪

      一直以来,C++模板给我带来的疑惑远大于帮助。 C++ 模板是丑陋的(ugly),笨拙的(clumsy),看看STL 和 BOOST 吧, 即使有丰富c++ 经验的人仍然会如坠云里雾中,恍若读天书一般。 C++ 模板的代码真的是太难读了。 好吧,即使我们不去关心模板的实现,当你使用它的时候也经常为之困扰。如果你用过Boost::bind 库,相信你一定会碰到过满屏的编译器错误信息,到头来问题只是缺少一个右括号而已。以上只是对C++ 的一些小抱怨罢了,C++模板最让人尴尬的是 它极易让人沉溺月语法糖中, C++ 模板中包含的概念真是太多了,以至于人们要不被它吓的望而却步, 要不一些人沉醉于奇技淫巧中。 因为C++ 它提供的概念越多, 诱惑就越多。程序员多多少少都有些自恋, 当程序员甲学会了一个语法技巧,便会迫不及待的应用到项目代码中, 但可能他的同伴程序员乙可能会看的一头雾水,丈二和尚摸不着键盘。

      话虽如此, c++ 也不是一无是处, 作为C 语言的面向对象的超集, 它成功的胜任了角色, 并且赢得了相当了不起的成就。 C++ 可以像C一样直接接触系统调用, 又具有面向对象的封装。 C++ 仍然是大型项目中主流的开发语言之一。

      我学习使用C++已经很长时间了, 一直在思考C++这门编程语言的价值所在。 这么多年, 有无数多人曾经诋毁过C++, 然而C++ 依然活跃着。究根起来, C++ 仍然具有不可替代性。 当处理系统级应用如TCP服务器程序、游戏服务器等,需要考虑一款静态类型语言; 没有人愿意从零开始, 拥有丰富的程序库是要考虑的重要因素之一; 面向对象的分析、设计正值当道, 面向对象的编码自然为情理之中; 如果再考虑一些平台移植性、性能等因素 在你的脑海里还存有多少选择呢? C++ 在这些应用中仍然是不二之选。 尽管它 概念繁杂, 代码也不美观, 可实际上没有人能拿出来新的东西代替它, 我觉得c++ 像是九阴白骨爪, 动作又丑陋,练起来又很复杂, 但是它杀伤了巨大, 练成此功必天下无敌。 好吧, 于是江湖上仍有不断默练此功之人, 有的功成名就, 有的则走火入魔,武功尽废。

      最近正在研究C++模板技术, 于是乎有了上面的一些心得体会。 看了一些C++ 模板库的例子, 在使用c++ 模板编程上我总结了一下心得:

1. 模板特化; 其实, 大部分模板库之所以得以能够使用起来如此飘逸, 都得益于模板特化的功劳。 我总结模板特化是“ 为达目的,不择手段的封装”。

2. 递归推导; c++ 模板的递归推导其实很神奇, 它能做的往往比你能够想到的要多的多。 我刚接触到它的时候,我就被震惊了, 原来c++ 编译器默默的做了这么多事情,这也是元编程的基础, 当然也是容易陷入语法糖的沼泽。 我总结为:“有趣的魔方”。 

3. 其它; 恕我才疏学浅, 许多特性还未参透, 不敢赘言。

下面是我练习时写的一个typelist, 它是一个容器, 存储的元素完全是类型。 这个typelist在C++ 模板库中也有类似的应用, 如tuple等。

1. 首先是两个辅助类型:

class null_type
{
};

struct empty_type
{
};

定义typelist 的原型

template <typename T, typename U>
struct typelist
{
       typedef T head;
       typedef U tail;
};

目前typelist 只能存储两个类型, 若要存储3个类型可能要这样使用:

typelist<int, typelist<long, char> >

上面使用了嵌套的方式, 当然随着容器的元素越来越多, 写出来将会变成一大坨!!

于是我们可以使用宏! 机器可以干的事情,就不要用手动(UNIX哲学)。


#define TYPELIST_1(T1) typelist<T1, null_type> 
#define TYPELIST_2(T1,T2) typelist<T1, TYPELIST_1(T2)>
#define TYPELIST_3(T1,T2,T3) typelist<T1, TYPELIST_2(T2,T3)>
#define TYPELIST_4(T1,T2,T3,T4) typelist<T1, TYPELIST_3(T2,T3,T4)>
#define TYPELIST_5(T1,T2,T3,T4,T5) typelist<T1, TYPELIST_4(T2,T3,T4,T5)>
#define TYPELIST_6(T1,T2,T3,T4,T5,T6) typelist<T1, TYPELIST_5(T2,T3,T4,T5,T6)>
#define TYPELIST_7(T1,T2,T3,T4,T5,T6,T7) typelist<T1, TYPELIST_6(T2,T3,T4,T5,T6,T7)>
#define TYPELIST_8(T1,T2,T3,T4,T5,T6,T7,T8) typelist<T1, TYPELIST_7(T2,T3,T4,T5,T6,T7,T8)>
#define TYPELIST_9(T1,T2,T3,T4,T5,T6,T7,T8,T9) typelist<T1, TYPELIST_8(T2,T3,T4,T5,T6,T7,T8,T9)>
.......

这里可以定义一坨的宏定义,这样我们可以飘逸的使用了:

typedef TYPELIST_9(int,long, string, int, long, string, int, long, string) my_typelist_t;

2. typelist 还不是完整的容器, 下面为其添加 type_length 方法, 计算typelist 的元素个数:

//! 定义一个工具模板类,计算typelist的类型个数, 只在编译时期完成计算。
template <typename TLIST> struct typelist_length;
首先是一个模板特化,我前边心得已经总结了, c++ 的模板很重要的是利用模板特化技术。

template <> struct typelist_length<null_type>
{
         enum { value = 0};
};

接下来则是一个模板的递归推导, 神奇的魔方, 我不会骗你:Look !! 
template <typename T, typename U>
struct typelist_length<typelist<T,U> >
{
         enum { value = 1 + typelist_length<U>::value};
};

吼吼!!, 就像运行期的程序一样, c++ 能够在编译器得到value的值。看来这已经有点程序产生程序的意味了。测试:

cout <<"length:"<< typelist_length<my_typelist_t>::value <<endl;

3. 继续丰富typelist 容器的接口, 这次我为其实现type_at 接口, 通过索引值找到对应的元素的类型。

老三样首先是类型原型:

template <typename TList, unsigned int index> struct type_at;

接下来就是模板特化, 哥说了,老三样,不会骗你:

template <typename T, typename U>
struct type_at<typelist<T,U>, 0>
{
       typedef typename typelist<T,U>::head result_type;
};

上面的代码曰 若索引值是0直接返回第一个类型, 接下来要干什么用屁股也能猜到了,模板递归推导:

template <typename T, typename U, unsigned int index>
struct type_at<typelist<T,U>, index>
{
       typedef typename type_at< U, index-1>::result_type result_type;
}; 测试如下:

cout <<"type_at:"<< sizeof(type_at<my_typelist_t,8>::result_type) <<endl;

4. 继续丰富typelist 容器的接口, 这次我为其实现index_of 接口, 通过目标类型值找到索引值, 跟上一个type_at 相反。

老三样, 哎呦真不想重复了, 这里可以写for 循环就好了。定义类型原型:

template <typename TList, typename T> struct index_of;

接下来进行模板特化:

template <typename T>
struct index_of<null_type, T>
{
       enum {value = -1};
};

template <typename HEAD, typename TAIL>
struct index_of<typelist<HEAD, TAIL>, HEAD>
{
       enum {value = 0};
};

这次总算有点新意, 利用了两次模板特化, 其实就是运行期的if else 一个道理,说实在的你叫一个C 程序员看这段代码, 会有什么感觉??? 它不是程序代码,也不是宏定义, 他是用来产生代码的代码, 那它是什么? 周星驰曰:“我要做乞丐中的霸主,那是什么?还是乞丐!”。 我们怎样理解这样一坨代码呢, 他们完全是为下面的递归推导而存在的,除此之外毫无意义。 就像我前面说的, 当你使用index_of 的时候你是不会意识到你使用了模板特化的,因为c++ 封装了这些, 所以我把它叫做“为达目的不择手段的封装”。 

template <typename HEAD, typename TAIL, typename T>
struct index_of<typelist<HEAD, TAIL>, T>
{
       enum {temp = index_of<TAIL,T>::value };
       enum {value = temp == -1? -1: 1+ temp};
};测试如下:

cout <<"index of:"<< index_of<null_type,int>::value <<endl;
cout <<"index of:"<< index_of<my_typelist_t,long>::value <<endl;

5. 继续丰富typelist 容器的接口, 这次我为其实现append_type 接口, 添加类型到typelist容器中。

template <typename TList, typename T> struct append_type;

template <>
struct append_type<null_type, null_type>
{
       typedef null_type result_type;
};

template <typename T>
struct append_type<null_type, T>
{
       typedef typelist<T,null_type> result_type;
};

template <typename T, typename U>
struct append_type<typelist<T, U>, null_type>
{
       typedef typelist<T,U> result_type;
};

template <typename T, typename U, typename R>
struct append_type<typelist<T, U>, R>
{
       typedef typelist<T, typename append_type<U, R>::result_type > result_type;
};

测试:

cout <<"append_type:"<< index_of<append_type<my_typelist_t,long long>::result_type, long long>::value <<endl;

6. 继续丰富typelist 容器的接口, 这次我为其实现erase_type 接口, 删除特定类型从typelist容器中。


template<typename TList, typename T> struct erase_type;

template<typename T>
struct erase_type<null_type, T>
{
       typedef null_type result_type;
};

template<typename HEAD,typename TAIL>
struct erase_type<typelist<HEAD, TAIL>, HEAD>
{
       typedef TAIL result_type;
};

template<typename HEAD,typename TAIL,typename R>
struct erase_type<typelist<HEAD, TAIL>, R>
{
       typedef typelist<HEAD, typename erase_type<TAIL, R>::result_type> result_type;
};

测试:

cout <<"erase_type:"<< typelist_length<erase_type<my_typelist_t,long>::result_type>::value <<endl;

7. 继续丰富typelist 容器的接口, 这次我为其实现erase_all 接口, 删除特定类型从typelist容器中,如果该类型在容器中有多个, 那么所有该类型都会被删除。

template<typename TList, typename T> struct erase_all;
template<typename T>
struct erase_all<null_type, T>
{
       typedef null_type result_type;
};

template<typename T, typename TAIL>
struct erase_all<typelist<T, TAIL>, T>
{
       typedef typename erase_all<TAIL, T>::result_type result_type;
};


template<typename HEAD, typename TAIL, typename T>
struct erase_all<typelist<HEAD, TAIL>, T>
{
       typedef typelist<HEAD, typename erase_all<TAIL, T>::result_type> result_type;
};

测试:

cout <<"erase_all:"<< typelist_length<erase_all<my_typelist_t,long>::result_type>::value <<endl;

8. 继续丰富typelist 容器的接口, 这次我为其实现erase_duplicate 接口,去除重复的类型。


template <typename TList> struct  erase_duplicate;
template <>
struct  erase_duplicate<null_type>
{
        typedef null_type result_type;
};


template <typename T, typename U>
struct  erase_duplicate<typelist<T,U> >
{
        typedef typename erase_duplicate<U>::result_type temp_type1;
        typedef typename erase_duplicate<temp_type1, T>::result_type temp_type2;
        typedef typelist<T, temp_type2> result_type;
};
测试:

cout <<"erase_duplicate:"<< typelist_length<erase_duplicate<my_typelist_t>::result_type>::value <<endl;

未完待续...................

 

相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载