jconcept
在GenericProgramming当中,一个重要的概念就是Concept(滑稽的是,如果把这个Concept也翻译成“概念”,那就狗屁不通了。我倾向于说它是“操作集”)。Concept就是一组操作,如果一个type具有这些操作,那么就说这个type是这个Concept的一个model。
这其中的思想有那么一丁点像是OO当中的interface,一个class如果实现了一个interface,那么它就可以被当作这个interface来用。同样,如果一个type是一个Concept的model,那么所有接受这个Concept的操作也就可以接受这个type。
例如,在STL中,stable_sort这个算法必须接受RandomAccessIterator,这里RandomAccessIterator就是一个Concept,它规定自己的model必须可以进行下标运算,那么不满足这个Concept的type就无法被编译器接受(搞笑的是我在VC71里面把list
C++语言本身并没有对于Concept的直接支持,STL解决这个问题的办法是用了一些traits来限制iterator的特性,以达到在编译时期检查Concept的目的。但是traits导致的编译错误提示实在是太可怕了,我非常怀疑有哪个正常人可以从这些错误提示推测出自己错在哪里。
在boost库里面,提供了一个ConceptCheck库,它可以帮助我们写出带有Concept检查的代码,而且没有运行时的开销,一旦用户违反Concept限制,输出的错误提示也比较好懂。举个例子先,如果STL里面有ConceptCheck,那么它的stable_sort大约会这样:
#include
template
voidstable_sort(RandomAccessIterfirst,RandomAccessIterlast)
function_requires
//…blablabla……
有了这个function_requires,如果再传递给它list的iterator,编译器(VC71)就会报这样的错:
c:boost_1_31_0boostconcept_check.hpp(642):errorC2676:二进制“+=”:“std::list<_Ty>::iterator”不定义该运算符或到预定义运算符可接收的类型的转换
_Ty=int
当然还有很多别的,但是至少它说了一点:传入的iterator不满足某个运算。这对于用户来说,应当是一个很有用的提示。
使用ConceptCheck还有一个额外的好处,那就是调用一个function_requires可远比写一些traits容易,而且代码也清晰好维护。
这个好用的function_requires就定义在concept_check.hpp当中:
template
inlinevoidfunction_requires(mpl::identity
#if!defined(NDEBUG)
void(Concept::*x)()=BOOST_FPTRConcept::constraints;
ignore_unused_variable_warning(x);
#endif
换句话说,function_requires只在Debug中起作用,那么是不是在Debug当中它就添加了overhead呢?其实也没有,仔细看看代码:
void(Concept::*x)()=BOOST_FPTRConcept::constraints;
这一句取constraints的地址。妙就妙在它让编译器“注意到”constraints,但又没有真正调用constraints,而constraints是一个虚函数,做实际的check。例如在RandomAccessIteratorConcept(检查iterator是否符合RandomAccessIterator的Concept)当中,constraint是这个样子:
template
structRandomAccessIteratorConcept
voidconstraints(){
function_requires
function_requires
#ifndefBOOST_NO_STD_ITERATOR_TRAITS
typedeftypenamestd::iterator_traits::iterator_categoryC;
function_requires std::random_access_iterator_tag>>(); typedeftypenamestd::iterator_traits::referenceR; #endif i+=n;//requireassignmentadditionoperator i=i+n;i=n+i;//requireadditionwithdifferencetype i-=n;//requireassignmentsubtractionoperator i=i-n;//requiresubtractionwithdifferencetype n=i-j;//requiredifferenceoperator (void)i[n];//requireelementaccessoperator TTa,b; TTi,j; #ifndefBOOST_NO_STD_ITERATOR_TRAITS typenamestd::iterator_traits::difference_typen; #else std::ptrdiff_tn; #endif 从这个实现中我们完全可以读出RandomAccessIterator的具体含义: 1.它必须是一个BidirectionalIterator 2.它必须满足“可比较(Comparable)”的Concept 3.它还必须满足“可转换(Convertible)”的Concept,而且是转换成自己的iterator_category类别 4.它必须定义了reference这个type 5.这是最重要的,它必须有difference_type,而且可以进行+,-,+=,-=的运算 还要记得,由于这个函数没有真正的被调用过,所以无论你怎么写,它都不会变成实际的代码,所以也不会影响运行效率的! boost库除了提供了一系列的ConceptCheck以外,也鼓励我们自己写ConceptCheck,至于写法,从这个RandomAccessIteratorConcept的写法,大家也可以看出些端倪了:很简单的。 本回答由提问者推荐 周杰伦(周董)即将发行第十二张个人专辑《十二新作》,12月12日於各大唱片行及7-11展开预购,於12月28日全亚洲同步推出喔 本回答由网友推荐 12月12号 2012年12月12日 本文来自投稿,不代表94汽车网(94che.com)立场,如若转载,请注明出处:94汽车网(94che.com)/qichezatan/379987.html