注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

一路

To find the final symmetry & beauty

 
 
 

日志

 
 
 
 

SGI STL源码阅读笔记4,concept check[原创]  

2011-02-15 16:36:20|  分类: c++学习笔记 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

    concept,model, refinement这些概念出自《Generic Programming and the STL》 by Matt Austern (Addison Wesley)一书,如果想知道详细内容可以阅读这本书。我这里只给出一个最基本介绍。知道面向对象的都知到继承和接口的概念,但是C++模版是在编译器计算的,没有哪个模版继承于另一个模版的概念。Concept model refinement的提出就是为了描述类似于类之间的继承关系,不过这些是应用于模板的。如果设共同特征A,我们设满足特征A为一个concept,如果某个type满足这个特征,那么就说这个type models这个concept,比如对于可以默认构造这个特征,我们把它定义为一个concept,那么比如int double 这些基本类型就满足这个特征,我们就说int 和double 都model这个concept. 对于自定义的类型,如果它们满足这个特征,那么它们也是这个concept下的model,也就models 这个concept.如果一个类型在一个concept下又能model另一个concept,那么这就叫做前一个concept下的refinement,这些就像继承一样,一个college_stuff继承自Person,而一个collega_teacher再继承自college_stuff,这就是在原关系上的加强(refinement)在同一组concept下相关于组成了代数中一个一个结构,在这个结构中可以保持运算不变。不过这个结构所做的运算是类型之间的运算罢了。本来concept model refinement 这些是要加入到c++标准0x中的,但是可能是考虑这种机制还不够成熟,如果加入可能对C++语言带来更多的限制而不是促使它发展,因此C++标准没有把它加入到language core中,不过可以通过类似于SGI STL库中使用的技术来做到这个功能,其中boost库中就也是concept check 库。

    要理解SGI STL concept check的工作方式,最直接的方式就是拆解其中一两个玩玩,自己尝试做一个简单的以加深理解。如果一个type不能model一个concept,那么我们就调用这个type对于此concept中的功能,如果调用失败就会出现语法错误,我们利用函数这个检查过程放在这个一个函数之中,这些函数都是使用类的模版函数,而且都是静态函数,这就是想利用模板的推迟实例法特性,静态函数基本不做任何实质性的工作,就算是能产生汇编代码,现代足够聪明的编译器也会把这部分汇编清除掉,因此concept check可以说完全是编译器在编期做的工作,不会给运行期带来任何开销。

    半于推迟实例化,看这里http://saturnman.blog.163.com/blog/static/557611201111524921187/

    关于concept_check.h代码,看这里http://saturnman.blog.163.com/blog/static/5576112011115258825/

先看代码

/ / This macro tests whether the template argument "     type_var"

/ / satisfies the requirements of "     concept". Here is a list of concepts

/ / that we know how to check:

/ /    _Allocator

/ /    _Assignable

/ /    _DefaultConstructible

/ /    _EqualityComparable

/ /    _LessThanComparable

/ /    _TrivialIterator

/ /    _InputIterator

/ /    _OutputIterator

/ /    _ForwardIterator

/ /    _BidirectionalIterator

/ /    _RandomAccessIterator

/ /    _Mutable_TrivialIterator

/ /    _Mutable_ForwardIterator

/ /    _Mutable_BidirectionalIterator

/ /    _Mutable_RandomAccessIterator

   

#define STL_REQUIRES( type_var, concept) \

do { \

void (* x)( type_var ) = concept##_concept_specification<

type_var >\     

:: concept##_requirement_violation; __x = __x; } while (0)

这是一个宏定义,##是一个连接字串的宏操作符,关于宏可以参考我以前的日志。我们把这个宏放在代码中编译一下看有什么结果,注意while循环是可运行代码,要放在函数中,SGI STL代码一般这些都是放在类的模版静态成员函数中,这是因为并不总是想这些宏被展开。我直接放在,main函数中测试,就让它展看以观其结果。 

//filename: concept_note.cpp

//written by saturnman

 

// This macro tests whether the template argument "__type_var"

// satisfies the requirements of "__concept".  Here is a list of concepts

// that we know how to check:

//       _Allocator

//       _Assignable

//       _DefaultConstructible

//       _EqualityComparable

//       _LessThanComparable

//       _TrivialIterator

//       _InputIterator

//       _OutputIterator

//       _ForwardIterator

//       _BidirectionalIterator

//       _RandomAccessIterator

//       _Mutable_TrivialIterator

//       _Mutable_ForwardIterator

//       _Mutable_BidirectionalIterator

//       _Mutable_RandomAccessIterator

 

#define __STL_REQUIRES(__type_var, __concept) \

do { \

  void (*__x)( __type_var ) = __concept##_concept_specification< __type_var >\

    ::__concept##_requirement_violation; __x = __x; } while (0)

class ClassA

{

    public:

        ClassA(){}

        //explicit write default constructor just to make things clear

};

int main()

{

    __STL_REQUIRES(ClassA,_DefaultConstructible);

    //original macro does'nt have a semicolon at the end,ATTENTION!

    return 0;

}

 

 

查看预处理后的代码,如下:

SGI STL源码阅读笔记4,chcept check[原创] - saturnman - 一路

 

好,这就很清楚了,这里是定义一个函数指针并初始化,这个函数指针是接受一个ClassA类类型,初始化的指针是模版类_DefaultConstructible_concept_specification的一个静态成员函数,这个函数的类型能与此处定义的函数指针匹配是因为类模版会把这个类类型传递给静态成员函数的,这个_DefaultConstructible不是随便选的,是预先定义好的,上面就有一个可选的列表。我们去查找这个类_DefaultConstructible_concept_specification的定义。因然在源文件下面我们找到了它的定义

SGI STL源码阅读笔记4,chcept check[原创] - saturnman - 一路

 

这个类的静态成员函数接受的类类型是模版类传给它的类型。这个静态成员函数再次调用一个工具类,_STL_
ERROR的一个静态模版成员函数对这个变量进行测试,注意其中所有的函数名都起的很长,这就是为了在出错时编译器打出的出错信息包括的函数名会给用户一些提示。我们继续查看这个工具类__STL_ERROR

SGI STL源码阅读笔记4,chcept check[原创] - saturnman - 一路

 

它的第一个成员就是这个静态模版函数,我们要测试一个类是否有默认构造函数,就要直接调用这个默认构造函数,如果失败就会出错,从而把这个静态成员函数的名称打出来。关于其它特性的测试都是使用类似这样的原里,测试某一功能有没就最直接的方式就是直接调用这个功能。这个默认构造函数是很简单的,我们再来看一个复杂的,这里有实现refinement的方法。

这里是双向迭代器的concept,从代码中就可以直接看出它先要求这个迭代器是一个单向的迭代器,之后再测试其是否为双向的迭代器,测试方法是调用其前++与后++的测试,这里还是使用工具类__STL_ERROR。

    好,通过我的描述你可能对concept model refinement的概念与其检测的实现有了一个了解了,这里还有一个地方不得不提一下。

#define STL_REQUIRES( type_var, concept) \

do { \

void (* x)( type_var ) = concept##_concept_specification<

type_var >\     

:: concept##_requirement_violation; __x = __x; } while (0)

 

看上面代码中使用一个do while 循环,这是宏的常用技巧。但是最后的__x = __x如何理解,这个一开始我也没有搞清楚,后来在网上找到了答案,这个是强行触发对类静态模版函数的实例化,如果不写上这名,类模版不会被实例化,其中的代码也不会被语法检查。我们所有的工作就都白费了。这也是推迟实例化的结果与避免它的方法J

 

Ref:

[1] <<Generic Programming and the STL>> by Matt Austern (Addison Wesley).

[2] http://en.wikipedia.org/wiki/C_preprocessor

[3] http://hi.baidu.com/walkandsing/blog/item/a61af5f86ecef209d9f9fd83.html

  评论这张
 
阅读(985)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017