人工低能

Artificial Imbecility(AI) may bedefined as the branch of IQ hat is concerned with the automation of imbecility behavior

原创 混沌 IN C++::Template Metaprograms收藏

新一篇: C++实践::Template实现Observer模式 | 旧一篇: 混沌 IN C++::模板参数的奥秘

难度:

 

文前说明:文中涉及到的观点并不是要求你去遵循它,而本文只相当于一篇“科普文章”。其中的关于template的语法在这里就不过多介绍了。例如,下文中提到的条件,都是要意识到是编译期常量。

C++ template 为我们提供了编译期计算的功能。编译器在处理template时,实际上相当于一个解释器的作用。充分利用template可以提高代码的运行速度,可以降低代码维护的复杂度,还可以为代码提供更具扩展性的能力。下面就尝试一下这样的编程方式。

 

一、  C++ template替代if/if-else语句

if(条件)

语句1;

else

语句2;

   

C++ template中,我们可以这样写

template<bool cond>

struct my_if{};

 

template<>

struct my_if<true>{

static void go()

{ 语句1; }

};

 

template<>

struct my_if<false>{

static void go()

{ 语句2; }

};

 

例如,我们判断两个整数

my_if<(1<5)>::go();

也许你会觉得这个if/if-elsetemplate有点大提小做的感觉,呵呵,继续往下看

 

二、  C++ template版的if/if-else扩展成能应付switch的代码

如果你是一个面向对象编程的高手,你肯定不会在你的代码中安置switch这样的代码,你肯定会用通过抽象、继承、多态和接口来完成这个任务。不过现在要换一个思维,用C++ template来实现。其实这里的代码和上面的if/if-else相差无几,但是在用于switch时,也同样能出色地体现出OC原则。

int i;

switch(i)

{

   case 1;

       语句1;

       break;

   case 2;

       语句2;

       break;

     default:

       语句3;

}

 

下面是C++ template版本

template<int I>

struct my_switch{

    static void go(){

         语句3;

}

};

 

template<>

struct my_switch<1>{

static void go()

{ 语句1; }

};

 

template<>

struct my_switch <2>{

static void go()

{ 语句2; }

};

 

调用就是my_switch<>::go();

你也许仍然找不出C++ template版本的switch好处,因为它要写更多的代码。不过你现在静下来认真的想一想,你会发现当你为switch插入新的值判断时,你要返回到switch处,而且还要修改内部的代码。而用C++ template却不需要你去关心my_switch到底在哪里定义的。要添加新的值判断时,只需要你自己在一个合适的地方添加值判断的代码。

 

三、  基于C++ template的数值运算

计算一个常数N的阶乘

template<int N>

struct factorial{

    static const int value = N * factorial<N-1>::value;

};

 

template<>

struct factorial<1>{

    static const int value = 1;

};

当这个类模板实例化factorial<N>,就会接着实例化factorial<N-1>,直到实例化fatorial<1>为止。而你只需要实例化自己想要计算的N就行了,后面的一切全由编译器包办。例如我们要输出10的阶乘答案

std::cout<<factorial<10><<std::endl;

 

四、  借助上面数值计算的方法以产生更实用的代码

是否考虑过得到指针的原型,比如通过int*,得到int。我们可以写出下面的代码

template<typename T>

struct primitive_type{

    typedef T value_type;

};

 

template<typename T>

struct primitive_type<T*>{

    typedef T value_type;

};

 

typedef int* pint;

primitive_type<pint>::value_type obj=5;

std::cout<<obj<<std::endl;

现在可以明确obj不是int*,而是int类型。但是有个缺陷就是但Tint**时却的不到int,而是得到的int*,这并不是我们想要的答案。现在只需要其实稍微对primitive_type的偏特化版本作下简单的修改,就可以满足要求

template<typename T>

struct primitive_type<T*>{

    typedef typename primitive_type<T>::value_type value_type;

};

 

typedef int**** pint;

primitive_type<pint>::value_type obj=5;  这个obj可以确认他是int,而不是int***

 

//The End

发表于 @ 2004年06月29日 05:28:00|评论(loading...)|编辑|收藏

新一篇: C++实践::Template实现Observer模式 | 旧一篇: 混沌 IN C++::模板参数的奥秘

评论

#iampolaris 发表于2004-06-29 12:36:00  IP: 218.199.143.*
晕呼呼
#Jensen Chen 发表于2004-06-29 12:58:00  IP: 61.141.231.*
大家看看 boost:: mpl 就什么都明白了。

template 当然是编译期的东西。但是有很多难以想象的运用。
Good luck.
#zhuk_nir 发表于2004-06-29 21:08:00  IP: 218.82.122.*
int i;
my_switch<i>::go();

可以吗???
#duyanning 发表于2004-06-29 13:05:00  IP: 222.90.12.*
to 游戏:看把你牛的,好像人家作者不知道一样
#Cynics 发表于2004-06-29 13:10:00  IP: 220.168.69.*
C++有时显得很诡秘(当女人有时捉摸不透时,才有激发你去了解她的动力)。
#young 发表于2004-06-29 21:49:00  IP: 221.232.122.*
template
不要用的太多,因为模板只有在需要的时候才会编译,
其结果是代码会膨胀。
#辣子鸡丁 发表于2004-06-29 13:33:00  IP: 222.183.140.*
你是正确的 不过我在最先已提到[而本文只相当于一篇“科普文章”]

to 别逗了
我的意思是只需要特化出
template<>
struct my_switch <新值>{
static void go()
{ 新语句; }
};
就OK了,呵呵,可能是我说的太神秘
#辣子鸡丁 发表于2004-06-29 23:18:00  IP: 222.183.140.*
>int i;
>my_switch<i>::go();
>
>可以吗???
当然不可以,在文的开头说道“下文中提到的条件,都是要意识到是编译期常量”
#辣子鸡丁 发表于2004-06-29 23:24:00  IP: 222.183.140.*
请不要拒绝模板,模板可以代替部分虚函数的功能。看看STL的做法
#别逗了 发表于2004-06-29 09:28:00  IP: 61.129.126.*
struct my_switch有点意思。但是,i是个变量,动态的。switch也是运行时刻判断执行分支的,这没问题。但是template怎么实现运行时判断执行分支呢?又怎么样做到“要添加新的值判断时,只需要你自己在一个合适的地方添加值判断的代码”?
#jink 发表于2004-06-30 09:42:00  IP: 218.108.40.*
模板是好东西,但没必要花太多的时间去研究他的怪异用法,标准的就够了,如果你实在闲得无聊就当我没说.
#游戏 发表于2004-06-29 10:56:00  IP: 61.152.132.*
1。将C++ template版的if/if-else扩展成能应付switch的代码
------瞎说,template是编译期的东东,如果没有用到的是不编译的,
看你的:
my_if<(1<5)>::go();
^^^^编译期可以确定,也就是如果没有my_if<false> 的话,那么特例化的my_if<false> 都不编译进去。
我想大家用if 绝大部分情况都是 if( 变量 ) 吧?
^^^^编译期不能确定
麻烦你用你的方法翻译一下下面的代码:
int b;
cin >> b;
if( b > 100)
cout<< " true " << endl;
else
cout<< " false" << endl;
那何况switch呢?

三是可以得,但是一个小错误:
std::cout<<factorial<10>::value<<std::endl;
^^^^^
始终记得,template是编译期要确定,你把很多运行期才能确定的东东都弄来了,思想本身就错了。
#Dreamer7901 发表于2004-06-30 10:05:00  IP: 221.239.81.*
都是高人啊,学习中
#lanzhengpeng 发表于2004-06-30 10:08:00  IP: 61.49.184.*
既然楼主这么有雅致,那么来欣赏下面这段代码,然后在看两遍后说出这段代码的功能
如果说不出来,就不要再发表类似这样的东西了。误人子弟,比他ma的谭浩强都不如。
C/C++本来是好东西,到了国内,就被一帮学究气的家伙给搞砸了。

template <class T>
struct remove_dimension
{
typedef T type;
};
template <class T, size_t N>
struct remove_dimension<T[N]>
{
typedef T type;
};

template <class T>
struct remove_all_dimensions
{
typedef T type;
};
template <class T, size_t N>
struct remove_all_dimensions<T[N]>
{
typedef typename remove_all_dimensions<T>::type type;
};

template <class T>
struct rank
{
static const unsigned value = 0;
};
template <class T, size_t N>
struct rank<T[N]>
{
static const unsigned value = 1 + rank<T>::value;
};

template <class T, unsigned I>
struct dimension
{
static const size_t value = 0;
};
template <class T>
struct dimension<T, 0>
{
static const size_t value = 0;
};
template <class T, size_t N>
struct dimension<T[N], 0>
{
static const size_t value = N;
};
template <class T, size_t N, unsigned I>
struct dimension<T[N], I>
{
static const size_t value = dimension<T, I-1>::value;
};
#Jeex 发表于2004-06-29 11:19:00  IP: 218.104.83.*
C++中的模板机制是turing-complete的,可以用递归模拟出分支和循环语句,这使得模板有能力成为一种通用编程语言,其风格为类似于Lisp的函数式语言。
#huaerbushi 发表于2004-06-30 15:45:00  IP: 210.72.241.*
不错,具有欣赏价值,欣赏一下,顺便给楼主点鼓励
#闻首 发表于2004-06-29 19:48:00  IP: 219.140.42.*
他的大部分代码,在多文件下时,特别是在多个项目下链接时就要出错。
#辣子鸡丁 发表于2004-06-30 14:01:00  IP: 222.183.141.*
既然你喜欢用代码讲话,那我也可以用代码讲话。如果你觉得我不知道其中的意思,而故意避开用文字描述,那么你就当我什么都不知道。:-P
int main(){
typedef int a5int[5];
remove_dimension<a5int>::type x=5;
cout<<x<<endl;
typedef int a10int[5][10];
remove_all_dimensions<a10int>::type y=5*10;
cout<<y<<"\n-------------"<<endl;

cout<<"about int[5]:"<<rank<a5int>::value<<endl;
cout<<"about int[5][10]:"<<rank<a10int>::value<<"\n-------------"<<endl;

cout<<"a10int includes "<<dimension<a10int,0>::value*dimension<a10int,1>::value
<<" elements"<<endl;
}
#辣子鸡丁 发表于2004-06-29 20:05:00  IP: 222.183.140.*
不会的,在其他文件之后进行全/偏特化是不会出现连接错误的,只有把声明和定义分别放在不同的文件中才出错。
#seacloud 发表于2004-06-29 20:10:00  IP: 61.170.213.*
个人认为如果BT的使用C++,后果将会是灾难性的。你想如果一大堆莫名其妙的代码里藏了一个虫子,呵呵,找的时候可能就会累死你。尤其是项目组成员C++水平参差不齐的时候。
其实,任何语言如果你硬要找茬的话,都是可以的。我们知道,C语言相比C++要干净很多,然而,用C照样可以写出如天书那样的程序来,这些程序一点都不比那些变态的Perl程序好读 ^_^
#lanzhengpeng 发表于2004-07-01 09:21:00  IP: 61.49.184.*
看了你的馄炖1234,又想到了大学时期学习C,那个时候,我已经使用C三年了,并且在DOS下开始操作中断,模拟多线程写程序了,可是我的C课程却没有及格。
如果搂主继续这么下去,除了知道孔乙己之外,没有什么实用用途。希望搂主不要再出来炫,把学风摆正。这才是软件开发的王道。
#别逗了 发表于2004-07-01 17:28:00  IP: 61.129.126.*
出来炫也不是问题,只要炫出点内容来就可以。
BS当初也没有想到Template Metaprograms,或者说还没有清晰的认识Template Metaprograms,这差不多BS的远见+无心插柳的产物。
其实,我们炫的这些东西实在不算什么。脱离了软件开发环境大谈什么可维护性,可理解性不过是空话而已。goto已经被抛弃了,可是,谁能说用了goto的程序一定就是垃圾?
#lanzhengpeng 发表于2004-07-02 09:47:00  IP: 61.49.106.*
看来这个switch你们也没有使用过
在我需要20多层递归推导的时候,我将内存使用上限开到800M才编译过去(实际使用似乎不需要这么多,可不设置编译器就报内部错误),并且需要编译1分钟左右(P4 2.4C)
这样的东西,后来还是放弃了使用——一是编译起来困难,二是我的同事看不懂。
#ckacka 发表于2004-07-01 21:48:00  IP: 218.6.242.*
四篇都看完了,真是精彩。^_^
留个名,看贴不回帖是要受到严重鄙视得。
#辣子鸡丁 发表于2004-07-02 00:23:00  IP: 222.183.142.*
谢谢 小红冒 和 别逗了 捧场,嘿嘿 鼓掌ING
#lover_P 发表于2004-07-01 13:17:00  IP: 218.107.145.*
[引用]你也许仍然找不出C++ template版本的switch好处,因为它要写更多的代码。不过你现在静下来认真的想一想,你会发现当你为switch插入新的值判断时,你要返回到switch处,而且还要修改内部的代码。而用C++ template却不需要你去关心my_switch到底在哪里定义的。要添加新的值判断时,只需要你自己在一个合适的地方添加值判断的代码。

=========================

那么,当别人或你自己数年后读到这些代码的时候呢?
#run_mei 发表于2004-07-02 18:17:00  IP: 218.80.155.*
下面是不是更牛可以
if_(condition)
[
statement
]

if_(condition)
[
true_statement
]
.else_
[
false_statement
]

具体实现如下

template <typename CondT, typename ThenT, typename ElseT>
struct if_then_else_composite {

typedef if_then_else_composite<CondT, ThenT, ElseT> self_t;

template <typename TupleT>
struct result {

typedef void type;
};

if_then_else_composite(
CondT const& cond_,
ThenT const& then_,
ElseT const& else__)
: cond(cond_), then(then_), else_(else__) {}

template <typename TupleT>
void eval(TupleT const& args) const
{
if (cond.eval(args))
then.eval(args);
else
else_.eval(args);
}

CondT cond; ThenT then; ElseT else_; // actors
};

//////////////////////////////////
template <typename CondT, typename ThenT>
struct else_gen {

else_gen(CondT const& cond_, ThenT const& then_)
: cond(cond_), then(then_) {}

template <typename ElseT>
actor<if_then_else_composite<CondT, ThenT,
typename as_actor<ElseT>::type> >
#少爷 发表于2004-07-02 09:30:00  IP: 61.152.124.*
继续,鼓励ing
#辣子鸡丁 发表于2004-07-03 06:47:00  IP: 222.183.140.*
to run_mei
>>下面是不是更牛可以
--------------------------------------
这样的code 能不牛X吗?因为需要,所以这样
boost::lambda
#leonao 发表于2004-07-09 14:17:00  IP: 210.42.98.*
都有见解,我主张的是实现需要的实现,真的不需要研究无聊的代码puzzle。
楼主只是给大家一个启示,我理解他的意思。当你需要,真的认为需要用template的时候,do it!在很多情况下它可以给你带来便利和效率上的提高。

建议大家看boost库的源码,哦,我指的是抱着学习思想而不是古怪代码的目的。
谢谢!
发表评论  


当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
Csdn Blog version 3.1a
Copyright © Jinhao