- 1、本文档共105页,可阅读全部内容。
- 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 5、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 6、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 7、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 8、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
boost源码剖析
boost源码剖析
?
谢轩 刘未鹏
C++的罗浮宫(/pongba)
在C++中侦测内嵌类型的存在(rev#2)
?
By 刘未鹏(pongba)
C++的罗浮宫(/pongba)
?
动机(Motivation)
假设一所大学的注册系统提供了一个注册函数:
?
templateclass T
void Register(T person)
{
Register(person, typename T::person_tag());
};
?
而对于注册者有以下几种标识:
?
struct student_tag{};
struct teacher_tag{};
?
还有Register的几个供内部使用的重载版本:
?
templateclass T void Register(T p, student_tag){...} // 注册学生
templateclass T void Register(T p, teacher_tag){...} // 注册教师
?
并规定学生类一定要在内部typedef student_tag person_tag,教师类typedef teacher_tag person_tag,这样,当传给起初的那个Register的对象为学生类对象时,typename T::person_tag()其实就构造了一个student_tag对象,从而激发函数重载,调用Register内部版本的templateclass T void Register(T p, student_tag)版本。其他情况亦均有对应。这是泛型编程里的常用手法(静态多态),STL里屡见不鲜。
?
问题是,现在学校里假如不止学生教师,还有工人,警卫等其它人员。如果他们不会在类内部typedef任何东西,则Register需要一种机制以确定T内部是否typedef了某个标识符(例如person_tag)。如果没有,就默认处理。如果有,则再进行更详细的分类。
?
实现(Implementation)
这个问题可能有两个实现途径。
?
一是利用函数重载,具体如下:
?
typedef char (yes_type)[1]; // sizeof(yes_type)==1
typedef char (no_type)[2]; // sizeof(no_type)==2
?
以上的两个typedef用于识别不同的重载函数。char ()[1]表示对char[1]数组的引用,所以sizeof(char()[1])==sizeof(char[1])==1。注意围绕符号的一对圆括号,它们是必要的,如果没有将会导致编译错误,正如char* [1]将被解析为char*的数组,char [1]将被解析为引用的数组,而后者是非法的。将用圆括号包围则改变了运算符的结合优先序,这将被解析为对char[1]数组的引用。
?
templateclass T
struct does_sometypedef_exists
{
templateclass U
static yes_type check(U, typename U::key_type* =0); // #1
static no_type check(...);
static T t; // 声明
static const bool value = sizeof(check(t))==sizeof(yes_type);
};
?
注意,#1处,*和=之间的空格是必要的,否则编译器会将它解析为operator*=操作符。
?
在我的VC7.0环境下,以下测试是成功的:
?
struct A{};
struct B
{
typedef int key_type;
};
int main()
{
std::cout does_sometypedef_existsA::value // 0
does_sometypedef_existsB::value // 1
std::endl;
};
?
下面我为你讲解它的原理。
?
当进行重载解析时,编译器会首先尝试实例化可以匹配的模板函数并将它们纳入到有待进行重载解析的函数的候选单之列,在本例中,当typename T::key_type不存在时,check的第一个模板版本不能实例化(因为其第二个参数类型typename U::key_type*不存在),所以只能匹配第二个版本。当typename T::key_type存在时,第一个模板函数可以实例化,且可以匹配(注意第二个参数为缺省参数),所以无疑编译器会匹配第一个版本,因为C++标准保证:只有当其它所有重载版本都不能匹配的时候含有任意类型参数列表的版本(在本例中那是no_type check(...))才
文档评论(0)