什麼時機下最合適選擇那種容器,依據:
1 元素多寡
2 元素構造複雜度
3 元素存取行爲特性
轉載出處:http://hi.baidu.com/walkandsing Matt Austern在Generic Programming and the STL中提出了Concept、Model、Refinement的概念,實際上是換湯不換藥,就是類似於Class、Object、SubClass的概念,只不過是在Template的語義下面解釋的而已,唯一的差別就是在Template下,類型是implicit的,對類型的要求比較鬆散。而所謂的Concept Checks就是類似於assert的東西,專業點講就是static assertion,就是利用編譯器在Compiling的時候的檢查來做一些檢查,例如: #define STATIC_ASSERTION(_cond,_name) typedef char STATIC_ASSERT_FAILED_ ## _name[(_cond)?1:-1] STL中和概念檢查有關的文件有:concept_checks.h、container_concepts.h、sequence_concepts.h和assoc_container_concepts.h。 先從concept_checks.h開始,這個文件定義了一些基礎的概念和iterator的概念,主要的接口是: #define __STL_CLASS_REQUIRES(__type_var, __concept): 檢查__type_var是否滿足__concept,當前定義的概念有:_Allocator、_Assignable、_DefaultConstructible、_EqualityComparable、_LessThanComparable、_TrivialIterator、_InputIterator、_OutputIterator、_ForwardIterator、_BidirectionalIterator、_RandomAccessIterator、_Mutable_TrivialIterator、_Mutable_ForwardIterator、_Mutable_BidirectionalIterator、_Mutable_RandomAccessIterator。 #define __STL_CONVERTIBLE(__type_x, __type_y) 檢查類型_x能否轉換爲類型_y。 #define __STL_CLASS_REQUIRES_SAME_TYPE(__type_x, __type_y): 檢查類型_x能否和類型_y爲同一個類型。 #define __STL_CLASS_GENERATOR_CHECK(__func, __ret): 用於在算法generate和generate_n中用來檢查generator合法性。 #define __STL_CLASS_UNARY_FUNCTION_CHECK(__func, __ret, __arg): 檢查__func的參數爲__arg類型,返回值爲__ret類型。 #define __STL_CLASS_BINARY_FUNCTION_CHECK(__func, __ret, __first, __second): 檢查__func的參數爲__first和__second類型,返回值爲__ret類型。 #define __STL_CLASS_REQUIRES_BINARY_OP(__opname, __ret, __first, __second): 檢查__ret __opname(__first, __second)是否合法。
在看這些接口的具體實現前,還需要了解一點他們的實現細節,在concept_checks.h中定義了一個類_STL_ERROR,裏面定義了一些static模板函數,這些方法組成了static assertion的最小單元: template <class _Type> static _Type __default_constructor_requirement_violation(_Type) { return _Type(); } template <class _Type> static _Type __assignment_operator_requirement_violation(_Type __a) { __a = __a; return __a; } ….(省略) 這些方法都是利用一些簡單的表達式使得編譯器來判斷__Type是否支持某一種操作,當其不支持的時候,compiler就會報錯,函數名將被打印出來,這樣用戶就能知道出錯的原因了。還有一些模板方法是用來檢測類型裏是否定義了某些typedef,如: template <class _Iter> struct __value_type_type_definition_requirement_violation { typedef typename __STD::iterator_traits<_Iter>::value_type value_type; };
template <class _Iter> struct __difference_type_type_definition_requirement_violation { typedef typename __STD::iterator_traits<_Iter>::difference_type difference_type; }; …. 然後基於這些atomic的static assertion組合出了一些概念: template <class _Type> struct _Assignable_concept_specification { static void _Assignable_requirement_violation(_Type __a) { _STL_ERROR::__assignment_operator_requirement_violation(__a); _STL_ERROR::__copy_constructor_requirement_violation(__a); _STL_ERROR::__const_parameter_required_for_copy_constructor(__a,__a); _STL_ERROR::__const_parameter_required_for_assignment_operator(__a,__a); } }; template <class _TrivialIterator> struct _TrivialIterator_concept_specification { static void _TrivialIterator_requirement_violation(_TrivialIterator __i) { typedef typename __value_type_type_definition_requirement_violation<_TrivialIterator>:: value_type __T; // Refinement of Assignable _Assignable_concept_specification<_TrivialIterator>:: _Assignable_requirement_violation(__i); // Refinement of DefaultConstructible _DefaultConstructible_concept_specification<_TrivialIterator>:: _DefaultConstructible_requirement_violation(__i); // Refinement of EqualityComparable _EqualityComparable_concept_specification<_TrivialIterator>:: _EqualityComparable_requirement_violation(__i); // Valid Expressions _STL_ERROR::__dereference_operator_requirement_violation(__i); } }; template <class _InputIterator> struct _InputIterator_concept_specification { static void _InputIterator_requirement_violation(_InputIterator __i) { // Refinement of TrivialIterator _TrivialIterator_concept_specification<_InputIterator>:: _TrivialIterator_requirement_violation(__i); // Associated Types __difference_type_type_definition_requirement_violation<_InputIterator>(); __reference_type_definition_requirement_violation<_InputIterator>(); __pointer_type_definition_requirement_violation<_InputIterator>(); __iterator_category_type_definition_requirement_violation<_InputIterator>(); // Valid Expressions _STL_ERROR::__preincrement_operator_requirement_violation(__i); _STL_ERROR::__postincrement_operator_requirement_violation(__i); } }; …. 到目前爲止,這些函數都是些函數調用,怎麼達到在編譯的時候判斷的目的呢?謎底就在接口定義中,以__STL_REQUIRES爲例,它的定義爲: #define __STL_REQUIRES(__type_var, __concept) / do { / void (*__x)( __type_var ) = __concept##_concept_specification< __type_var >/ ::__concept##_requirement_violation; __x = __x; } while (0)
比如在很多算法的開頭都有檢查: __STL_REQUIRES(_InputIter, _InputIterator);
評論:定義函數指針不會觸發模板實例化,指針賦值使編譯器會靜態檢查模板內部實現。 這時相當於在block裏定義了一個函數指針__x,而__x=__x將觸發模板的實例化,這時編譯器開始對_InputIterator_concept_specification::_InputIterator_requirement_violation中的所有的static assertion進行檢查,但又不會調用這些函數,這樣只會在編譯期間會產生開銷。 其他的接口定義也都類似,值得一提的還有__STL_CONVERTIBLE和__STL_REQUIRES_SAME_TYPE,實際上在Modern C++ Design中有提到這兩個模板,但我發現在STL中這兩個模板的實現更加簡潔。 template <class _TypeX, class _TypeY> struct _STL_CONVERT_ERROR { static void __type_X_is_not_convertible_to_type_Y(_TypeX __x, _TypeY) { _TypeY __y = __x; __sink_unused_warning(__y); } }; #define __STL_CONVERTIBLE(__type_x, __type_y) / do { / void (*__x)( __type_x , __type_y ) = _STL_CONVERT_ERROR< __type_x , / __type_y >::__type_X_is_not_convertible_to_type_Y; / __x = __x; } while (0) 很簡單,就是通過賦值來判斷的。 template <class _Type> struct __check_equal { };
template <class _TypeX, class _TypeY> struct _STL_SAME_TYPE_ERROR { static void __type_X_not_same_as_type_Y(_TypeX , _TypeY ) { __check_equal<_TypeX> t1 = __check_equal<_TypeY>(); } }; #define __STL_REQUIRES_SAME_TYPE(__type_x, __type_y) / do { / void (*__x)( __type_x , __type_y ) = _STL_SAME_TYPE_ERROR< __type_x, / __type_y >::__type_X_not_same_as_type_Y; / __x = __x; } while (0) 這個稍微麻煩一點,雖然也是通過賦值來判斷但引入了一個空模板__check_equal,當_TypeX和_TypeY類型不同的時候,__check_equal<_TypeX>和__check_equal<_TypeY>肯定不同,即使_TypeX和_TypeY是convertiable的,__check_equal<_TypeX>和__check_equal<_TypeY>的賦值也是非法的。 在container_concepts.h和sequence_concepts.h中的方法和上述類似,在此不再累述。 |