免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 7198 | 回复: 10
打印 上一主题 下一主题

[C++] Modern C++ Design(MCD)学习笔记 && 测试代码 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-02-04 15:49 |显示全部楼层 |倒序浏览
MCD里面给我们展现了许多高阶的C++ template技巧,大部分都是天才级别的人才能想出来的,与此同时,这些技巧也稍显前卫了,至少根据我对国内C++程序员的了解,能把STL玩的很好的已经少见了,并且里面的大部分技巧是在“挑战编译器”。

但是,我还是决定好好把这本书看完,一边看一边摘录书中以及loki库中的代码进行测试,权当开阔自己的视野。

一.compile assert编译器断言技巧

// 以下是书中的代码
template<bool> struct CompileTimeError;
template<> struct CompileTimeError<true>{};

#define STATIC_CHECK(expr)  \
    (CompileTimeError< (expr) != 0>() )

template<bool> struct CompileTimeChecker
{
    CompileTimeChecker(...);
};

template<> struct CompileTimeChecker<false> {};

#define STATIC_CHECK_MSG(expr, msg) \
    {\
        class ERROR_##msg {};\
        (void)sizeof(CompileTimeChecker<(expr)> (ERROR_##msg()));\
    }

// 以下是loki中的代码
namespace Loki
{
        template<int> struct CompileTimeError;
        template<> struct CompileTimeError<true> {};
}

#define STATIC_CHECK_LOKI(expr, msg) \
{ Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg;}

int main(int argc, char *argv[])
{
        // gcc不能编译,VC7编译通过
    STATIC_CHECK(1);
        // gcc,VC7都不能编译
    //STATIC_CHECK_MSG(1, Error_Msg);
        // gcc,VC7都能编译
        STATIC_CHECK_LOKI(1, Error_Msg);

    return 0;
}


这个东东的技巧在于:定义一个模版类,这个模版的模版参数是bool类型,对true的特化模版类进行了定义,而false的特化类没有定义,在使用的时候把需要断言的表达式作为模版参数来初始化这个模版类,如果为false,因为false的特化类没有定义,此时编译器会报错。

注意:这里的断言是在编译期进行的,与一般的运行时断言有区别。

论坛徽章:
0
2 [报告]
发表于 2007-02-04 15:58 |显示全部楼层
原帖由 mik 于 2007-2-4 15:55 发表
呵,弱弱地问:MCD是什么?


弱弱的回答:您仔细看贴了么?

论坛徽章:
0
3 [报告]
发表于 2007-02-04 23:13 |显示全部楼层
二.检查是否可以转换以及是否存在继承关系的类

/********************************************************************
        created:        2007/02/04
        filename:         CanConverse.cpp
        author:                Lichuang
               
        purpose:       
*********************************************************************/
#include <iostream>

using namespace std;

template <class T, class U>
class Conversion
{
private:
        // sizeof(char) == 1,这是标准规定的
        typedef char Small;
        // sizeof(Big) == 2 * sizeof(char) > sizeof(char)
        class Big        { char dummy[2]; };
        // Test型别是U,返回值是Small
        static Small Test(U);
        // Test型别是任意型别,返回值是Big
        static Big Test(...);
        // 返回一个T型别的值
        static T MakeT();

public:

        // exists的值反映了T是否可以转换为U
        // MakeT首先返回一个T型别的值, 传入Test()中
        // 如果编译器确定T可以转换为U,那么调用返回Small的Test函数
        // 否则调用返回Big的Test函数,则sizeof(Big) != sizeof(Small)
        // 对于一般的型别如int, char,double,float而言只是进行隐性的转换
        // 但是对于传入类指针的情况而言,那么派生类的指针可以转换为基类的指针
        // 也正是基于这一点可以作为检查两个类是否有继承关系的技巧
        enum
        {
                exists = sizeof(Test(MakeT())) == sizeof(Small)
        };

        // 型别T,U是否可以双向转换
        enum
        {
                exists2Way = exists && Conversion<U, T>::exists
        };

        // 是否是同一个型别
        enum
        {
                sameType = false
        };
};

// 针对同一个型别的模版偏特化类
template <class T>
class Conversion<T, T>
{
public:
        enum
        {
                exists = 1,
                exists2Way = 1,
                sameType = 1
        };
};

// 检查U是否是T的派生类的宏
// 第一条语句检查是否存在U*向T*的转换,如果存在上述关系那么派生类指针U*可以转换为基类指针T*
// 第二条检测派生类指针是不是和void*是一个型别的
#define SUPERSUBCLASS(T, U)        \
        (Conversion<const U*, const T*>::exists &&        \
        !Conversion<const T*, const void*>::sameType)

class Base
{
};

class Derive
        : public Base
{
};

class Test
{
};

int main()
{
        cout << Conversion<double, int>::exists << ' ' << endl;

        if (SUPERSUBCLASS(Base, Derive))
        {
                cout << "can derive\n";
        }
        if (!SUPERSUBCLASS(Base, Test))
        {
                cout << "Can not derive\n";
        }

        return 0;
}


说明的注释都在sample代码里面了,我想无需做太多的解释,直接看代码就好了。

论坛徽章:
0
4 [报告]
发表于 2007-02-08 00:25 |显示全部楼层
三.typelists--递归思想的美妙体现

typelists是一个模板类,里面用模板存放了类型的信息,你可以通过这个类获得有关类型的信息,可以添加,删除,替换其中的类型,但是,这是一个没有数据成员的类,所有的操作都是在编译器进行的。

typelist的风格很像lisp,是递归思想的美妙体现。

类定义:
// 表示类型链表中的最后一位,相当于字符串中最后的'\0'
class NullType {};

// 头类型和尾类型都是模板
template <class T, class U>
struct Typelist
{
        typedef T Head;
        typedef U Tail;
};

链表中保存的类型都是模板,因此也可以把Typelist自己作为模板参数,也正是这个特性使得所有它的操作中递归思想体现的淋漓尽致。
NullType 是一个空类型,用于表示链表的末尾,有点类似于字符串中的'\0'。

以下是两个为了实现typelists方便而出现的宏和类:
// 仅保存一个类型的typelist
#define TYPELIST_1(T1) Typelist<T1, NullType>

// 根据传入的模板参数生成一个类型链表,注意默认类型是NullType
template<typename T1 = NullType, typename T2 = NullType, typename T3 = NullType>
struct MakeTypelist
{
private:
        typedef typename MakeTypelist<T2, T3>::Result TailResult;

public:
        typedef Typelist<T1, TailResult> Result;
};

// 对没有模板参数的偏特化类定义
template<>
struct MakeTypelist<>
{
        typedef NullType Result;
};

[ 本帖最后由 converse 于 2007-2-8 00:29 编辑 ]

论坛徽章:
0
5 [报告]
发表于 2007-02-08 00:40 |显示全部楼层
续上....

好了,现在开始查看与typelist的相关操作了.

前面说了,typelist是递归思想的美妙体现,因此在下面的相关操作中,都有一般情况,终止情况还有递推的情况,一般情况是针对最泛化的模板类实现,终止情况是针对nulltype(还记得我们前面说过nulltype表示链表的结束么)的实现,而递推情况是针对一般情况的递推。

1)返回typelist的长度的模板类

/********************************************************************
        返回typelist长度的模板类
*********************************************************************/
template <class TList>
struct Length;

// 一般情况
template <class T, class U>
struct Length< Typelist<T, U> >
{
        static const int value = 1 + Length<U>::value;
};

// 对于NullType返回0,这是终止情况
template <>
struct Length<NullType>
{
        static const int value = 0;
};


Length的技巧在于:一个typelist的长度 = 1 + 除去头节点之后剩下的链表长度。回忆前面提到的typelist中的两个类型一个是head一个是tail,那么除去头节点之后剩下的链表就是tail了。
如果你看懂了上面的实现,也许已经开始嗅到一些递归的味道了吧~~

论坛徽章:
0
6 [报告]
发表于 2007-02-08 00:45 |显示全部楼层
续上...

2)根据index返回在typelist中该index所在位置的类型的模板类

********************************************************************
        根据index返回在一个typelist中位于这个index的类型,index从0开始
*********************************************************************/
template <class TList, int index>
struct TypeAt
{
        typedef typename TypeAt<typename TList::Tail, index - 1>::Result Result;
};

template <class Head, class Tail>
struct TypeAt<Typelist<Head, Tail>, 0>
{
        typedef Head Result;
};


这个模板类的思想与前面的length十分类似,比如:
一个typelist<int, typelist<char, double> >要求返回index=2的类型,
第一次调用为typelist<char, double>,index - 1 =1,
第二次调用为typelist<double,nulltype>, index - 1 = 0,此时head = double返回之~~

论坛徽章:
0
7 [报告]
发表于 2007-02-08 00:48 |显示全部楼层
续上...

3)根据typelist中的类型返回index的模板类

/********************************************************************
        根据typelist中的类型返回index,index从0开始
*********************************************************************/
template<class TList, class T>
struct IndexOf
{
private:
        static const int temp = IndexOf<typename TList::Tail, T>::value;

public:
        static const int value = (temp == -1 ? -1 : 1 + temp);
};

// 对于Typelist中的Tail返回0
template <class T, class Tail>
struct IndexOf<Typelist<T, Tail>, T>
{
        static const int value = 0;
};

// 对nulltype返回-1
template <class T>
struct IndexOf<NullType, T>
{
        static const int value = -1;
};


与typeat算法类似,不多阐述了。注意index是从0开始的。

论坛徽章:
0
8 [报告]
发表于 2007-02-08 00:54 |显示全部楼层
困的不行,先把测试代码放上来,有兴趣的自己可以编译运行看看,gcc,vc7均编译通过了

/********************************************************************
        created:        2007-2-7
        filename:         typelists.cpp
        author:                Lichuang
       
        purpose:       
*********************************************************************/

#include <iostream>

// 表示类型链表中的最后一位,相当于字符串中最后的'\0'
class NullType {};

// 头类型和尾类型都是模板
template <class T, class U>
struct Typelist
{
        typedef T Head;
        typedef U Tail;
};

#define TYPELIST_1(T1) Typelist<T1, NullType>

// 根据传入的模板参数生成一个类型链表,注意默认类型是NullType
template<typename T1 = NullType, typename T2 = NullType, typename T3 = NullType>
struct MakeTypelist
{
private:
        typedef typename MakeTypelist<T2, T3>::Result TailResult;

public:
        typedef Typelist<T1, TailResult> Result;
};

// 对没有模板参数的偏特化类定义
template<>
struct MakeTypelist<>
{
        typedef NullType Result;
};

/********************************************************************
        返回typelist长度的模板类,递归思想的美妙体现
*********************************************************************/
template <class TList>
struct Length;

//
template <class T, class U>
struct Length< Typelist<T, U> >
{
        static const int value = 1 + Length<U>::value;
};

// 对于NullType返回0,这是起始情况
template <>
struct Length<NullType>
{
        static const int value = 0;
};

/********************************************************************
        根据index返回在一个typelist中位于这个index的类型,index从0开始
*********************************************************************/
template <class TList, int index>
struct TypeAt
{
        typedef typename TypeAt<typename TList::Tail, index - 1>::Result Result;
};

template <class Head, class Tail>
struct TypeAt<Typelist<Head, Tail>, 0>
{
        typedef Head Result;
};

/********************************************************************
        根据typelist中的类型返回index,index从0开始
*********************************************************************/
template<class TList, class T>
struct IndexOf
{
private:
        static const int temp = IndexOf<typename TList::Tail, T>::value;

public:
        static const int value = (temp == -1 ? -1 : 1 + temp);
};

// 对于Typelist中的Tail返回0
template <class T, class Tail>
struct IndexOf<Typelist<T, Tail>, T>
{
        static const int value = 0;
};

// 对nulltype返回-1
template <class T>
struct IndexOf<NullType, T>
{
        static const int value = -1;
};

/********************************************************************
        添加一个类型到typelist的后面
*********************************************************************/
template <class TList, class T>
struct Append;
// 在typelist中一直查找nulltype下去,找到的时候就把类型添加进去返回
template <class Head, class Tail, class T>
struct Append<Typelist<Head, Tail>, T>
{
        typedef Typelist<Head, typename Append<Tail, T>::Result> Result;
};

template <class Head, class Tail>
struct Append<NullType, Typelist<Head, Tail> >
{
        typedef Typelist<Head, Tail> Result;
};

template <class T>
struct Append<NullType, T>
{
        typedef TYPELIST_1(T) Result;
};

template <>
struct Append<NullType, NullType>
{
        typedef NullType Result;
};

/********************************************************************
        移除typelist中某个类型的第一次出现
*********************************************************************/
// 当head == T的时候,这个查找过程结束,返回Tail
// 否则将一直查找下去
template<class TList, class T>
struct Erase
{
        typedef Typelist<typename TList::Head, typename Erase<typename TList::Tail, T>::Result> Result;
};

template <class T, class Tail>
struct Erase<Typelist<T, Tail>, T>
{
        typedef Tail Result;
};

template <class T>
struct Erase<NullType, T>
{
        typedef NullType Result;
};

template<class TList, class T>
struct EraseAll
{
        typedef Typelist<typename TList::Head,
                typename EraseAll<typename TList::Tail, T>::Result> Result;
};

/********************************************************************
        移除typelist中某个类型的所有出现
*********************************************************************/
template <class T, class Tail>
struct EraseAll<Typelist<T, Tail>, T>
{
        typedef typename EraseAll<Tail, T>::Result Result;
};

template <class T>
struct EraseAll<NullType, T>
{
        typedef NullType Result;
};

/********************************************************************
        移除typelist中某个类型的重复出现,只留下最开始的一个
*********************************************************************/
template <class TList>
struct NoDuplicates;

template <class Head, class Tail>
struct NoDuplicates< Typelist<Head, Tail> >
{
private:
        typedef typename NoDuplicates<Tail>::Result L1;
        typedef typename Erase<L1, Head>::Result L2;

public:
        typedef Typelist<Head, L2> Result;
};

template <>
struct NoDuplicates<NullType>
{
        typedef NullType Result;
};

/********************************************************************
        把typelist中某个类型替换为另一个类型
*********************************************************************/
template<class TList, class T, class U>
struct Replace
{
        typedef Typelist<typename TList::Head, typename Replace<typename TList::Tail, T, U>::Result> Result;
};

template <class T, class Tail, class U>
struct Replace<Typelist<T, Tail>, T, U>
{
        typedef Typelist<U, Tail> Result;
};

template <class T, class U>
struct Replace<NullType, T, U>
{
        typedef NullType Result;
};

using namespace std;

int main()
{
        typedef MakeTypelist<int, char, double>::Result typelist;
        int i = Length<typelist>::value;
        cout << "length of typelists is " << i << endl;

        TypeAt<typelist, 2>::Result d = 0.123;
        cout << "num = " << d << endl;

        i = IndexOf<typelist, int>::value;
        cout << "index of int in typelist is " << i << endl;

        typedef Append<typelist, float>::Result typelist2;
        i = IndexOf<typelist2, float>::value;
        cout << "index of float in typelist2 is " << i << endl;

        typedef Erase<typelist2, float>::Result typelist3;
        i = IndexOf<typelist3, float>::value;
        cout << "index of float in typelist3 is " << i << endl;

        typedef MakeTypelist<int, char, char>::Result typelist4;
        typedef EraseAll<typelist4, char>::Result typelist5;
        i = IndexOf<typelist5, char>::value;
        cout << "index of char in typelist5 is " << i << endl;

        typedef NoDuplicates<typelist4>::Result typelist6;
        i = IndexOf<typelist6, char>::value;
        cout << "index of char in typelist6 is " << i << endl;

        typedef Replace<typelist, double, unsigned char>::Result typelist7;
        i = IndexOf<typelist7, unsigned char>::value;
        cout << "index of unsigned char in typelist7 is " << i << endl;

        return 0;
}

论坛徽章:
0
9 [报告]
发表于 2007-02-08 21:38 |显示全部楼层
续上...

4)添加一个新类型到typelist中

/********************************************************************
        添加一个类型到typelist的后面
*********************************************************************/
template <class TList, class T>
struct Append;
// 在typelist中一直查找nulltype下去,找到的时候就把类型添加进去返回
template <class Head, class Tail, class T>
struct Append<Typelist<Head, Tail>, T>
{
        typedef Typelist<Head, typename Append<Tail, T>::Result> Result;
};

template <class Head, class Tail>
struct Append<NullType, Typelist<Head, Tail> >
{
        typedef Typelist<Head, Tail> Result;
};

// 针对nulltype的偏特化,此时已经查找到链表尾,生成一个只含有一个类型的typelist返回
template <class T>
struct Append<NullType, T>
{
        typedef TYPELIST_1(T) Result;
};

// 针对空链表的偏特化
template <>
struct Append<NullType, NullType>
{
        typedef NullType Result;
};


查找typelist一直到查找到nulltype也就是链表结束的地方,生成一个只含有新增加的类型的typelist返回。

论坛徽章:
0
10 [报告]
发表于 2007-02-08 21:41 |显示全部楼层
续上...

5)移除某个类型的第一次出现

/********************************************************************
        移除typelist中某个类型的第一次出现
*********************************************************************/
// 当head == T的时候,这个查找过程结束,返回Tail
// 否则将一直查找下去
template<class TList, class T>
struct Erase
{
        typedef Typelist<typename TList::Head, typename Erase<typename TList::Tail, T>::Result> Result;
};

// 当head == T时把tail返回
template <class T, class Tail>
struct Erase<Typelist<T, Tail>, T>
{
        typedef Tail Result;
};

template <class T>
struct Erase<NullType, T>
{
        typedef NullType Result;
};


当需要移除的类型为head时,把tail返回达到移除的效果。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP