分享
 
 
 

元编程技法(1)——if_c

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

一直想整理一下对于meta-programming的一些想法,就从这个最简单的开始吧!

if_c是boost::mpl库提供的一个元编程算法,它接受三个模板参数,第一个是bool类型,后面两个是类型名:

template<

bool c

, typename T1

, typename T2

>

struct if_c

{

typedef unspecified type;

};

它的作用是,如果c为true,则type为T1;反之type为T2。如果要用伪代码来表达这个算法的意思,就是

if(c)

type = T1

else

type = T2

现在可以来看看这个算法的用途了,下面的模板函数PrintLarger接受两个类型模板参数,并且在控制台输出较大的一个类型的名字。

template <typename T1, typename T2>

void PrintLarger()

{

typedef boost::mpl::if_c<(sizeof(T1)>sizeof(T2)),

T1,

T2

>::type T;

std::cout << typeid(T).name() << std::endl;

}

例如,在Win32平台下,PrintLarger<int, double>会输出double,而PrintLarger<int, bool>输出int。不要小看这个算法,在元编程的世界里,它扮演的角色非同小可。作为一个基础构件,它提供了在编译期间进行逻辑判断并选择编译“路径”的方法,对于编译期计算来说,其意义不下于运行时计算中的if...else语句。

这个算法是怎样实现的呢?很简单,它用到的是在C++元编程中最常用的武器:模板偏特化。通过模板偏特化来影响编译器行为的做法在STL里面比比皆是,只不过STL并没有把它作为一个算法而已。而boost::mpl库则把它提炼出来,为更高阶的抽象提供了一个很好的基础。下面就来看看if_c算法的实现。

利用模板偏特化的算法一般分为两个阶段:一般定义阶段和特化定义阶段。一般定义提供了算法的一般“形状”,而特化定义则提供特殊路径下的行为。if_c的一般定义是这样的:

template<

bool C

, typename T1

, typename T2

>

struct if_c

{

typedef T1 type;

};

也就是说,直接令type=T1就可以。但是我们希望C==false的时候,type=T2,该如何处理呢?这就是特化定义上场的时候了。它特别指出,当C==false的时候,type应该为T2:

template<

typename T1

, typename T2

>

struct if_c<false,T1,T2>

{

typedef T2 type;

};

注意这里的语法,特化值false不出现于模板参数列表中,而是直接跟在if_c之后。这两个定义合起来告诉编译器:if_c的第一个模板参数是一个bool值,如果它为false,那么采取特化定义,也就是typedef T2 type这一句;在其他的情况下(在这里,当然只有C==true啦),采取一般定义,也就是typedef T1 type。整个判断在编译期间就已经完成,不但不会消耗运行时期的时间,而且还可以轻易地办到在运行时很不好实现的一些事情,如上述的根据大小选择类型。

从if_c算法中,我们可以一窥元编程的一些特点:首先,元编程操作的往往是类型,一个算法通过模板机制来接受参数,而通过内部的typedef来返回结果类型;其次,统一的命名对于元编程具有重要意义,在if_c中,结果类型被命名为type,而这个命名就像运行时算法中的函数命名一样,只要大家都知道并且遵守,就可以很好的交流。如果一个使用者不知道if_c的计算结果类型叫做type,那就根本无法使用它。在元编程的世界里,这样一些约定叫做Concept,Concept可以看作是比类型更高的一层抽象,它规定了一个类型应该像什么样子(有点类似于接口)。如果一个类型满足一个Concept的要求,那么它就叫做这个Concept的一个Model,从而就可以参与所有要求这个Concept的计算。这一点有点类似于实现了一个接口的类实例可以参与所有要求该接口的计算一样。

了解了这个最简单的算法,下面可以对它进行一些推广:我们希望让第一个模板参数不只是单纯的bool类型,而是“任何可以被转换成bool类型的”类型。可以把这个算法命名为if_,这也是boost::mpl库提供的算法之一。我们希望这个算法的形状是:

template<

typename T1

, typename T2

, typename T3

>

struct if_

{

typedef unspecified type;

};

现在,希望if_的行为是:如果T1可以被转换成true,则type=T2;如果T1可以被转换成false,则type=T3;如果都不可以,那么就应该报错。幸运的是,编译期算法如果出错,一定是编译错误,不会造成运行时候的麻烦。

在这里,需要解决的第一个难题是:T1是一个类型,而true和false都是一个值,这两者之间怎么可能转换呢?命名规范又要大显身手了,我们可以约定:被用作T1的类型必须定义一个“可被转换成true或false的静态成员”,名字叫value。有了这个约定,我们就可以放心大胆的编写if_算法,而用户如果强行把不符合该约定的类型放到T1的位置,那么编译器一定会阻止这种愚蠢的做法。说到这里,if_算法的实现已经呼之欲出了,它直接利用了if_c算法:

template<

typename T1

, typename T2

, typename T3

>

struct if_

{

typedef typename if_c<(bool)T1::value, T2, T3>::type type;

};

boost::mpl库的if_算法实现与这个异曲同工,只不过它的实现考虑了更多可移植性问题,支持Lambda表达式,并且使用了boost::static_cast函数,代码比较复杂。

现在只需要定义一个带有成员value的类型,就可以使用if_算法了。

struct TrueT

{

static const int value = 1;

};

...

if_<TrueT, int, double>::type v; //此处v为int类型的变量

在这个简单的例子中,似乎if_比if_c麻烦了许多,因为if_c根本无须定义什么TrueT,只需要直接传入一个true就可以达到目的。但是,使用类型作为参数让if_可以直接使用其他的编译期算法,如果这些算法都遵守关于定义一个value成员的约定,那就可以节省不少的代码。更重要的是,它提升了抽象的级别:判断的依据不但可以是bool值,而且是“任何可以得出bool值的类型”。当然,我们往往不需要更高的抽象,所以正如Windows API很多都有增强的“Ex版本”一样,可以把if_看做if_c的增强版本,而我们应该根据场合选择合适的版本。

元编程为我们打开了一个神奇的世界,在这里可以实现许多在运行时世界里不可思议的事情。最妙的是,这些实现都不会消耗运行时间,它们所占用的资源仅仅是空间和编译时间而已。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有