说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

关一个关于C++模板的问题

编辑:说三道四文库 发布时间:2017-03-30 03:18
HTML文档下载 WORD文档下载 PDF文档下载
现在我有一个接口,比如说是 
class ISupportInitialize
{
public:
    virtual void Initialize() = 0;    
}

然后有一个模板函数
template<class T> void function( T t );
 在函数中我想根据T是否从接口派生做一些不同的事,比如说T从ISupportInitialize派生,
我就调用 t.Initialize() 方法,否则就不调用。

请问题如何实现这样的功能
namespace __inner
{
    template<typename _T> char fun(_T*);
    template<typename _T> long fun(...);
}

template<typename _Base, typename _Sub>
struct is_same_type
{
    enum{value = sizeof(char) == sizeof(__inner::fun<_Base>((_Sub*)0)) };
};


class ISupportInitialize
{
public:
virtual void Initialize() = 0;
};

class Foo: public ISupportInitialize
{
public:
    virtual void Initialize(){ cout<<"Initialize"<<endl; };
};

template<bool>
class dispatcher
{
public:
    template<typename _T>
    dispatcher(_T& r){}
};

template<> class dispatcher<true>
{
public:
    template<typename _T>
    dispatcher(_T& r)
    {
        r.Initialize();
    }  
};

template<class T> void function( T t )
{
    (dispatcher<is_same_type<ISupportInitialize, T>::value>(t));           
}

int main()
{
   Foo x;
   int y;
   function(x);
   function(y);
}
template<typename _T> char fun(_T*);
template<typename _T> long fun(...);
第三次看到这个用法了,很是巧妙..
学习
学习ing
谢谢 Jinhao(辣子鸡丁·新年新气象) ,我现在正在看 Modern C++ Design 这本书,里面关于模板的介绍真是让人大开眼界。以后还要多向你请教 :)
>>template<> class dispatcher<true>
改成template<> class dispatcher<false>
为什么连编译都过不了, 请高手解释!(只要求能编译, 不管逻辑是否正确)

写的很好,佩服!
template<typename _T> char fun(_T*);
template<typename _T> long fun(...);
这个技巧到处都有,并不稀奇,但是整体封装的挺好的!
谁来答答我上面的问题
http://community.csdn.net/Expert/topic/4552/4552060.xml?temp=9.527224E-02
答案找到了...本贴的偏特化编译用得好!
全特化 -_-!
mark
呵呵,鸡丁好像很喜欢特化。佩服。

namespace __inner
{
    template<typename _T> char fun(_T & t){};
    template<typename _T> long fun(...){};
}

template<typename _Base, typename _Sub>
bool is_derived_from(_Sub & s)
{
    return sizeof(char) == sizeof(__inner::fun<_Base>(s)); 
}


class ISupportInitialize
{
public:
virtual void Initialize() = 0;
};

class Foo: public ISupportInitialize
{
public:
    virtual void Initialize(){ cout<<"Initialize"<<endl; };
};

void main()
{
    Foo f;
    if(is_derived_from<ISupportInitialize>(f))
             f.Initialize();

}
可以看看Boost提供的那些对于类型判断的模板,。
不过还是很佩服前面几位的代码。
利用模板偏特化可以实现
int main()
{
    Foo f;
    if(is_derived_from<ISupportInitialize>(f))
             f.Initialize();
}

其实这样来判断,这段代码就失去意义了。如果f没有Initialize,那么将导致一个编译错误
学习
(=_=)
真他们的越来越佩服鸡丁了 (=_=)
学习
#include<iostream>
using namespace std;

namespace __inner
{
template<typename _T> void  fun(_T*t){ t->Initialize();}
template<typename _T> void  fun(...){cout<<"...."<<endl;}
}
class ISupportInitialize
{
public:
virtual void Initialize() =0;
};

class Foo: public ISupportInitialize
{
public:
int i;
void Initialize(){ cout<<"Initialize:  "<<i<<endl; };
};


template<typename T>
void Proxy(T t)
{
__inner::fun<ISupportInitialize>(&t);
}
int main()
{
Foo x;
x.i=10;
int y=0;

Proxy(x);
Proxy(y);
}

唉,研究了一下,做了个变体出来,供参考
鸡丁啊......................(=_=)
SammyLan...你把要做的事情移到了fun里面 使得更直接一点. 但是有时可能太直接了也不便于扩展,或者另做它用.呵呵
其实这样来判断,这段代码就失去意义了。如果f没有Initialize,那么将导致一个编译错误
------------

NO, 如果本身f没有Initialize,它的基类也必须要有,否则在定义Foo f的时候就会因为包含了纯虚函数而出错,到不了后面判断的那一步。

所以基本上个人认为判断“Foo是不是ISupportInitialize”的派生类,就可以完成90%以上的“Foo有没有已实现的Initialize”的判断了,

我倒是觉得,如果是一个private 继承,似乎是没有办法了。但作为接口,private继承还是少的。
template<> class dispatcher<true>
{
public:
    template<typename _T>
    dispatcher(_T& r)
    {
        r.Initialize();
    }  
};

template<class T> void function( T t )
{
    (dispatcher<is_same_type<ISupportInitialize, T>::value>(t));           
}
-------------------------------
认真看了一下,其实这一段跟俺那一段不是等价的么?is_same_type<>::value得到true或者false,然后根据true/false决定是否调用t.Initialize()


不过你说的那个问题是对的,就是说,如果Foo本身没有实现Initialize(),但是其基类曾经实现过,比如:

class ISupportInitialize
{
public:
virtual void Initialize() = 0;
};

class Temp: public ISupportInitialize
{
public:
    virtual void Initialize(){ cout<<"Initialize"<<endl; };
};

class Foo: public Temp
{
};
 
这个时候就会很糟糕,换一种方式可能会好一些。

void main()
{
    Foo f;
    if(is_derived_from<ISupportInitialize>(f))
    {
        ISupportInitialize * pBase = &f;
        pBase->Initialize();
    }

}

什么是特化?
鸡丁兄。请教一下。。小弟看不明白
(dispatcher<is_same_type<ISupportInitialize, T>::value>(t));   
这里的外层括号的作用是什么??
(dispatcher<is_same_type<ISupportInitialize, T>::value>(t));
这里。相当于
dispatcher<is_same_type<ISupportInitialize, T>::value>  _dispatcher(t);
术语上我不知道要怎么解释。。但是外层括号的作用就是省掉定义一个对像

不知道我这样说正不正确。。
外层的括号可以去掉。

 xxxdg(学习中) 的代码
如果Foo 不是从ISupportInitialize派生,则你的程序编译会不通过。
 Jinhao的代码是利用了模板的一个特性:如果一段模板代码没有被用到,则它不会被编译。所以不会报编译借
(dispatcher<is_same_type<ISupportInitialize, T>::value>(t));
最外边这一层括号不能去掉
如果要去掉最外层的话,那么就必须这么写
dispatcher<is_same_type<ISupportInitialize, T>::value> _dispatcher(t);

其中上面这段和下面的等同
dispatcher<is_same_type<ISupportInitialize, T>::value> (_dispatcher)(t);

所以,如果去掉最外面层,
dispatcher<is_same_type<ISupportInitialize, T>::value>(t);
其实就是
dispatcher<is_same_type<ISupportInitialize, T>::value> t;

最后在来看看 function
template<class T> void function( T t )
{
(dispatcher<is_same_type<ISupportInitialize, T>::value>(t));
}
如果去掉最外层括号,那么就成了
template<class T> void function( T t )
{
  dispatcher<is_same_type<ISupportInitialize, T>::value> t;//t?重复定义!
}
MK
That is not important.
It is a never-committed crime.
---------------------------------
int main(int argc, char *argv[])
{
    Foo f;
    if(is_derived_from<ISupportInitialize>(f))
    {
        ISupportInitialize * pF = (ISupportInitialize *)&f;
        pF->Initialize();
    }        
    int k;
    if(is_derived_from<ISupportInitialize>(k))
    {
        ISupportInitialize * pF = (ISupportInitialize *)&k;
        pF->Initialize();
    }        
  system("PAUSE");
  return 0;
}
--------------------------------------------------
模板特化是好的,不过我个人认为像条件判断等一些基本语法,还是保留原始语法更好一些,显得简洁。编程风格的问题,Not necessarily. Any way,I have sent my ADMIRATION. :)
MK!
学习
ri.....
枉我自诩学过c++,熟练vc,竟没读懂。。。。
目录所占的字节数-VB资料 VB判断文件是否在IE的缓存中 屏蔽文本框的右键菜单-VB资料 VB取得长文件名 VB取得临时文件名 VB取得某个目录底下所有文件大小总和 VB取得文件的扩展名 VB取得文件内容 确定 TextBox 有几行-VB资料 确定是 WINDOWS 的可执行文件-VB资料 让打印机只打印一行-VB资料 VB如何把批处理文件转换成EXE文件? VB如何调用 Office VB如何将文件删除到回收站 VB如何快速移动文件? VB如何让文本框输入完后,直接跳入下一行? VB如何使用vb取得一个文件的控制权 VB如何使用文件复制对话框? VB如何使用资源文件 VB如何用Dir()函数来列出C下所有TMP文件并且用文本框输出 VB如何在 VB 中使用 Winzip 来压缩文件? VB如何在DOS程序结束执行时,自动将其关闭? VB如何在VB中实现Undo(撤消)功能? VB如何在VB中实现目录遍历 VB如何在Windows操作系统中改变文件打开方式 VB如何知道硬盘是使用那一种文件系統(FAT32,FAT16)? VB如何自动更动成中文输入 VB删除整个目录 VB设置打印页边距 VB实现文件查找功能 VB使用SendMessage函数滚动文本框控件中的内容 Rational Rose 中没有Delphi方面得模块,哪儿有与Delphi接口下载 谁有ActiveReport 2的中文例子和原程?在线等待!急急急! 大家来讨论一下,《设计模式》应该怎么看!! 关于打印的问题,高手关注! datagrid如何实现分页,。net菜鸟 声音问题 access数据库加密后,如何再用ADO与之连接? 有谁用过ms Agent? 很菜的问题! delphi里的widestring类型对应着BCB里的什么类型啊 开了一个socket,acept后如何给ie发一个字符串显示出来? access数据库加密后,如何再用ADO与之连接? 如何查询出所有用户表名 PWS中的一个小问题 请问DataSet里的Relations和Constraints有什么区别? 想了三天,还是做不出 请问如何创建一个大于屏幕分辨率的窗口? 公开putao的最大秘密,他女友的隐私! 关于不同版本的用户对象的问题!(online) 在批处理中设置路径,有空格系统不认怎么办? 为了忘却的纪念(今天是咱们的国耻日) 关于JSP菜单实现的问题? 如何判断数组是否被赋值? 用MSCHART的二维折线图如何实现左右坐标分别标识不同的曲线? 请问招行的网上银行的在网上点击安装是怎么实现的呀? 100分只是开始。。。 如果回答继续加!! 一个template问题,想不出办法,高手请进 送分题:如何改变dll的调试可执行文件? 大家看看代码 真搞不懂为什么出错??? 如何在表单中设置包含字段http://schemas.microsoft.com/cdo/workflow/response 如何使用VBSCRIPT读取本页文本框中的数据, (不能用表单提交和JAVASCRIPT 能不能?) 我在桌面上执行一个应用程序,运行正常,但用pb中调用run("***.exe")运行是出错,提示是少了某些dll文件 我怎么才能使客户端发过来的经UF8编码的中文URL,还原成GD312,能找到页面? 我用openwithparm(w_1,arg),arg明明传递的是LONG型的数据,为什么用message.longparm接收到的是0,而一定要用message.doubleparm才能正确 问一个sql语句如何写,简单! 征集能够同时输出文本和图形的控件! 急寻bmp转gif的代码 封装在Dll中的窗口焦点问题 为什么我用JBUILDER编译JSP文件,用web run执行后会出现这些情况?? 有谁用过CMPPE2.0协议开发过网关程序的请进 win2000下内存使用的问题? 我每次都结贴子的,不信你们查一下啊,这次再请帮忙,谢谢哦 在公共文件夹如公告窗体的原件与回复件是如何关联的? delphi中form中放了一副图,怎样让图可见而form不可见? 一个关于vba的应用问题?合并文档 英文版的vb中该如何来把一个项目进行打包呢(想把它安装到一台没有装vb 的电脑上) 删除多余的重复记录 如何获取屏幕尺寸? 有人用过EasyPack的仿真器吗? 关于QuickRpt报表存盘后出现乱码的问题。 邮件监测器要怎么写?? 我的爸爸作文 怎样写只要说出第一自然段写什么好,怎样开头,然后第二自然段怎样写,一直接下去说.(写好加分)其实不用写这么多,比如:开头写样子,第二自然段写什么,第三自然段写 以孔子或孟子的一句话写一篇600字作文 又见校园作文350~450字 作文开头 “我的父亲……” 这是第几人称? 用孔子或孟子的一句名言,写一篇700字作文 2009年国庆节阅兵式文章 孔子弟子及其再传弟子所编篡的儒家经典著作是哪一部? 请用孔子或孟子的某一句名言为题,写一篇作文儒家文化对中华民族的发展影响至深,孔子和孟子离我们的时代已十分久远,然而他们那杰出的智慧和伟大的人格,仍然会给有益的启迪.请以孔子 若入射光线的方向不变,而将平面镜转过Q角,则反射光线转过的角度是 我的父亲作文,结尾 孔子著作的儒家的经典著作《 》虽然只短短五千字,却流芳百世 我因什么而自豪作文 我的爸爸作文结尾简短一点 《论语》是儒家学派经典著作之一,内容记录孔子及其门徒的( ),与( ),( ),( )合称‘四书’ 我因什么而自豪600字初一作文 四年级的作文:我和_____(350字左右) 《论语》这本书是儒家的经典著作,从语录中看,孔子认为学习的快乐在于?各位大侠们帮帮我吧! 我因什么而自豪作文,我想写警察无论刮风下雨维护社会的秩序,有这样的人感到自豪……帮我想下开头结尾 初中生的水平 好的+分啊!一楼的 我不是要抄整篇文章啊…………只是帮我想下开头 帮我写一篇关于廉洁修身的征文,700字左右 小明要做一个对角线互相垂直的等腰梯形形状的风筝,其面积为2450平方厘米,则它的对角线的长为多少? 急求寒假社会实践活动心得体会2000字... 用一块面积为450cm^2的等腰梯形彩纸做风筝,为了牢固起见,用……用一块面积为450cm^2的等腰梯形彩纸做风筝,为了牢固起见,用竹条做梯形的对角线,对角线恰好互相垂直,那么至少需要竹条______cm 【要解题过程】一个对角线互相垂直的等腰梯形形状的风筝,其面积为2450平方厘米,则它的对角线的长答案这个方程:2450=a×a/2 a=70怎么算的啊? 作文有趣的一件事 一束光线与水平面成30°角向下照射时,想让光线经平面镜反射后沿水平方向射出,则入射角可能是( ) A.15° B.45° C.75°D.A.B.C三者都有可能 (要说明理由,为什么选这个答案.谢谢了.) 和父母写信交流600字作文 作文《一件有趣的事》要有趣,最好能体现出有趣在哪里,开头结尾要符合,就这样! 作文:爸爸我想对你说开头和结尾 孔子为什么创建儒学 要有哲理性 多一点 越多越好 初一作文:我骄傲,我 (勇敢 自信……都可以)马上就要,不要太离谱,500-600字初一水平就行了,会的帮下,谢谢大哥大姐.(我是男的)急需,不要太离谱,500字左右,初一水平,不用很好,能 一束光线与水平面成30度从右上方向左下方射入.通过一平面镜的反射,要使光线水平向右射出则平面镜与水平面的夹角为( )要使光线向右射出,则平面镜与水平面的夹角为( ) 孔子在哪里创立儒家学派在什么地方 开学畅想,我要350字的 爸爸给我的爱...这篇作文的开头和结尾...要靠谱,谢啦... 为什么孔子创立的学派被称为儒家? 作文 老师 我想对你说350 一束光线与水平面成30度夹角,要使反射光线沿水平方向传播,那么平面镜与水平方向所成的夹角为多大?平面镜作在哪? 孔子是在什么时期创建儒家学派的?急! 帮我想一下一件有趣的事←作文600字左右的! 在课外活动课上,老师让同学们做一个对角线互相垂直且相等的四边形形状的风筝,其面积为450cm²,问 对所用的竹条至少需要多长?(还没学梯形) 用面积为200平方厘米的等腰梯形彩纸做风筝,用竹条做梯形的对角线,对角线垂直,至少需要竹条多少厘米 智慧做人的七大学问 读后感. 描写爸爸外貌的作文需要两句描写句,最好再另付10句描写,多一句加一分. 阅兵式作文600字 文具店第一天卖出玩具小狗98个,每个获利润44.1元.第二天卖出133个,利润是成本的40%.第一天卖出的个数与第二天相同,求每个玩具小狗的成本是多少元?错了,应该是钱数相同 在课外活动课上,老师让同学们做一个对角线互相垂直的等腰梯形形状的风筝,其面积是450平方厘米问:对角线所用的竹条至少需多少厘米 《廉洁修身》的作文 关于读后感的作文要怎么写? 孔子的思想为什么叫儒学 600字阅兵式作文急急急!规范各繁华过后孤鸿寡鹄今天就要?(=@__@=)哪里有?要有国家领导的介绍,今天就要还要有士兵介绍 作文:观60周年国庆阅兵式有感 孔子为什么建立儒家 怎么写"廉洁修身"的论文?我要知道的是怎么去写"廉洁修身"的论文的方法.而不是要一篇文章来抄哦.教教我方法. 作文:观国庆60周年阅兵式有感450字就行了··· 孔子的儒学为何称儒 《廉洁修身》作文应怎样写? 谁能帮我弄1个国庆阅兵式有感的作文? 关于廉政的作文450字 关于孔子或孟子的名言的作文以孔子或孟子的某一句名言为题,写一篇议论文,600字左右.注意立论要有依据. 观阅兵式有感09年作文最少不能低于400字
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘