『STL 的六大组件containers, algorithms, iterators, function objects, allocators, adaptors, 全都是concepts,实作品如vector, list, sort(), swap() 等等templates, ... 全都是models。』
『所谓concept 和model
所谓concept,描述某个抽象型别的条件(或说需求,requirements)。concept 并不是一个class,也不是一个变数或是一个template 参数;C++(www.cppentry.com) 语言之中没有任何东西可以直接代表一个concept。然而,在每一个用到泛型程式设计方法的C++(www.cppentry.com) 程式中,concept 非常重要。由concepts 所构成的阶层体系,正是STL 的主体结构。
当某个型别满足某个concept 的所有条件,我们便说此型别是该conecpt 的一个model。concept 可被视为一组型别条件。如果型别T 是concept C 的一个model,那么T 就一定满足C 的所有条件。因此,concept 亦可被视为是一组型别。如果型别T 是concept C 的一个model,我们便可说T 隶属于「C 所表现的一组型别」。』
使用版本:boost 1.50.0
通常程式的bug大致上可以区分为三种:
第一种是编译时期的错误
第二种是run-time时期的错误:通常是因为物件被删除、pointer指到null或memory leak而导致程式执行期间的crash。
第三种则是程式逻辑计算上的错误:因为整个程式运作上不会有任何问题,因此非常难以定出错误的问题所在。
boost中的concept check机制的目的,便是想要处理第一种bug--目的是要让C++(www.cppentry.com)中因泛型编辑所产生的编译错误能够更清楚的显示出他的问题到底出在哪,而不是一堆对使用者而言毫无意义的错误讯息。
例如,如果我们编译下面的内容:
#include <vector>
#include <algorithm>
#include <complex>
#include "boost/concept/assert.hpp"
#include "boost/concept/requires.hpp"
#include "boost/concept_check.hpp"
int main( int , char *[]) {
std::vector<std::complex< float > > v;
std::stable_sort(v.begin(), v.end());
system( "pause" );
return 0;
}
在VS2008下产生的编译错误讯息如下:
1>------ Build started: Project: BoostLibraryPractice, Configuration: Debug Win32 ------
1>Compiling...
1>main.cpp
1>c:\program files\microsoft visual studio 9.0\vc\include\xutility(294) : error C2784: 'bool std::operator <(const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem * )' : could not deduce template argument for 'const std::basic_string<_Elem,_Traits,_Alloc> &' from 'std::complex<float>'
1> c:\program files\microsoft visual studio 9.0\vc\include\string(150) : see declaration of 'std::operator <'
1> c:\program files\microsoft visual studio 9.0\vc\include\algorithm(2760) : see reference to function template instantiation 'bool std::_Debug_lt<std::complex<float>,std::complex<float> >(_Ty1 &,_Ty2 &,const wchar_t *,unsigned int)' being compiled
1> with
1> [
1> _Ty1=std::complex< float >,
1> _Ty2=std::complex< float >
1> ]
1> c:\program files\microsoft visual studio 9.0\vc\include\algorithm(3400) : see reference to function template instantiation 'void std::_Buffered_merge<_BidIt,_Diff,_Ty>(_BidIt,_BidIt,_BidIt,_Diff, _Diff,std::_Temp_iterator<_Ty> &)' being compiled
1> with
1> [
1> _BidIt=std::_Vector_iterator<std::complex< float >,std::allocator<std::complex< float >>>,
1> _Diff=__w64 int ,
1> _Ty=std::complex< float >
1> ]
1> c:\program files\microsoft visual studio 9.0\vc\include\algorithm(3412) : see reference to function template instantiation 'void std::_Stable_sort<_BidIt,_Diff,_Ty>(_BidIt,_BidIt,_Diff,std: :_Temp_iterator<_Ty> &)' being compiled
1> with
1> [
1> _BidIt=std::_Vector_iterator<std::complex< float >,std::allocator<std::complex< float >>>,
1> _Diff=__w64 int ,
1> _Ty=std::complex< float >
1> ]
1> c:\program files\microsoft visual studio 9.0\vc\include\algorithm(3421) : see reference to function template instantiation 'void std::_Stable_sort<std::_Vector_iterator<_Ty,_Alloc>,__w64 int,std: :complex<float>>(_BidIt,_BidIt,_Diff *,_Ty *)' being compiled
1> with
1> [
1> _Ty=std::complex< float >,
1> _Alloc=std::allocator<std::complex< float >>,
1> _BidIt=std::_Vector_iterator<std::complex< float >,std::allocator<std::complex< float >>>,
1> _Diff=__w64 int
1> ]
1> c:\workspace\dropbox\workspace\boostlibrarypractice\boostlibrarypractice\main.cpp(13) : see reference to function template instantiation 'void std::stable_sort<std::_Vector_iterator<_Ty,_Alloc>>(_BidIt,_BidIt) ' being compiled
1> with
1> [
1> _Ty=std::complex< float >,
1> _Alloc=std::allocator<std::complex< float >>,
1> _BidIt=std::_Vector_iterator<std::complex< float >,std::allocator<std::complex< float >>>
1> ]
1>Build log was saved at "file://c:\workspace\Dropbox\workspace\BoostLibraryPractice\BoostLibraryPractice\Debug\BuildLog.htm"
1>BoostLibraryPractice - 1 error(s), 0 warning(s)
对我们程式设计师而言,其实这堆讯息显示的错误都不是我们所关心的。我们想知道的是,到底是什么原因造成这段程式编译错误。到底,传入的型别在操作上的概念上出了什么问题?
先回头来看看concept跟model的定义:型别T如果符合concept C所条件,那么型别T就是concept C的一个model。
型别T也可以同时符合多个不同concept,当然,也会是多个不同concept的model。在上面的例子中,std::stable_sort这个方法会有许多预设在操作上的概念,因为它STL中的一个方法,因此一定会符合其规范的一些基本concepts:Assignable、Default Constructible、Equality Comparable、LessThan Comparable。
从错误讯息中,对比较有经验的程式设计师而言,其实是可以推断出错误是由于型别std::complex<float>没办法在std::stable_sort中进行大小的比较所造成的。以比较专业的术语来说的话,便是其不符合LessThanComparable concept条件而产生的错误。因此std::complex<float>不是LessThanComparable concept的model。
因此,这个错误是由于传入的型别不对所造成的,因此显示STL内部的错误讯息没办法很直觉的告知问题是出在user code上而不是library code中。
因此,在对std::stable_sort导入concept check的机制之后,其型式变成这样:
#include <vector>
#include <algorithm>
#include <complex>
#include "boost/range/concepts.hpp"
using namespace boost;
template < class RandomAccessIter>
void my_stable_sort(RandomAccessIter first, RandomAccessIter last){
//所有basic concept在boost/range/concepts.hpp都有实作了
function_requires<RandomAccessIteratorConcept<RandomAccessIter> >();
typedef typename std::iterator_traits<RandomAccessIter>::value_type value_type;
function_requires< LessThanComparableConcept<value_type> >();
//do stable sort algorithm
std::stable_sort(first, last);
}
int main( int , char *[]) {
std::vector<std::complex< float >> v;
// std::vector<float> v;
my_stable_sort(v.begin(), v.end());
system( "pause" );
return 0;
}
产生的错误码:
1>------ Build started: Project: BoostLibraryPractice, Configuration: Debug Win32 ------
1>Compiling...
1>main.cpp
1>c:\workspace\library\boost_1_50_0\boost\concept_check.hpp(247) : error C2784: 'bool std::operator <(const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem *)' : could not deduce template argument for 'const std::basic_string<_Elem,_Traits,_Alloc> &' from 'value_type'
1> c:\program files\microsoft visual studio 9.0\vc\include\string(150) : see declaration of 'std::operator <'
1> c:\workspace\library\boost_1_50_0\boost\concept_check.hpp(246) : while compiling class template member function 'boost::LessThanComparable<TT>::~LessThanComparable(void)'
1> with
1> [
1> TT=value_type
1> ]
1> c:\workspace\library\boost_1_50_0\boost\concept_check.hpp(244) : see reference to class template instantiation 'boost::LessThanComparable<TT>' being compiled
1> with
1> [
1> TT=value_type
1> ]
1> c:\workspace\library\boost_1_50_0\boost\concept\detail\has_constraints.hpp(42) : see reference to class template instantiation 'boost::LessThanComparableConcept<TT>' being compiled
1> with
1> [
1> TT=value_type
1> ]
1> c:\workspace\library\boost_1_50_0\boost\concept\detail\msvc.hpp(53) : see reference to class template instantiation 'boost::concepts::not_satisfied<Model>' being compiled
1> with
1> [
1> Model=boost::LessThanComparableConcept<value_type>
1> ]
1> c:\workspace\library\boost_1_50_0\boost\concept_check.hpp(45) : see reference to class template instantiation 'boost::concepts::require<Model>' being compiled
1> with
1> [
1> Model=boost::LessThanComparableConcept<value_type>
1> ]
1> c:\workspace\dropbox\workspace\boostlibrarypractice\boostlibrarypractice\main.cpp(14) : see reference to function template instantiation 'void boost::function_requires<boost::LessThanComparableConcept<TT>>(Model *)' being compiled
1> with
1> [
1> TT=value_type,
1> Model=boost::LessThanComparableConcept<value_type>
1> ]
1>Build log was saved at "file://c:\workspace\Dropbox\workspace\BoostLibraryPractice\BoostLibraryPractice\Debug\BuildLog.htm"
1>BoostLibraryPractice - 1 error(s), 0 warning(s)
我们可以发现,错误变的更加显而易见了。