前一篇文章中说了SGI STL中的Concepts Check,其实就是利用模板类类实例化在编译期会执行检查的特性. SGI STL大量运用了
Concepts Check,前面已经说过,这里不再多说.在<<C++ Primer>>中在"模板与泛型编程"章节中有讲解模板的特化,不再赘述.
模板特化分为两种: 1. 绝对特化
2. 部分特化
在这片博文中,主要来看一下部分特化.依旧是选用stl_stack.h源码.
template <class _Tp, class _Sequence __STL_DEPENDENT_DEFAULT_TMPL(deque<_Tp>) >
宏__STL_DEPENDENT_DEFAULT_TMPL只是简单的用来实现默认模板参数的指定:
# define __STL_DEPENDENT_DEFAULT_TMPL(_Tp) = _Tp
看看Stack模板类实现中的这两行源码:
__STL_CLASS_REQUIRES(_Sequence, _BackInsertionSequence);
下面这个__STL_CLASS_REQUIRES宏都做了哪些事情?
#define __STL_CLASS_REQUIRES(__type_var, __concept) \ typedef void (* __func##__type_var##__concept)( __type_var ); \ template <__func##__type_var##__concept _Tp1> \ struct __dummy_struct_##__type_var##__concept { }; \ static __dummy_struct_##__type_var##__concept< \ __concept##_concept_specification< \ __type_var>::__concept##_requirement_violation> \ __dummy_ptr_##__type_var##__concept
这个宏与前面解释的__STL_CLASS_REQUIRES_SAME_TYPE宏类似,就依据需要检查的参数_BackInsertionSequence来看看在Stack
中进行了哪些检查.跳转就会找到源码:
template <class _BackInsertionSequence> struct _BackInsertionSequence_concept_specification { static void _BackInsertionSequence_requirement_violation(_BackInsertionSequence __s) { // Refinement of Sequence _Sequence_concept_specification<_BackInsertionSequence>::_Sequence_requirement_violation(__s); // Valid Expressions _ERROR_IN_STL_SEQ::__back_function_requirement_violation(__s); _ERROR_IN_STL_SEQ::__push_back_function_requirement_violation(__s); _ERROR_IN_STL_SEQ::__pop_back_function_requirement_violation(__s); }
模板中有一个静态函数,函数中首先调用了__Sequence_concept_sepcification模板中定义的另一个静态函数__Sequence_requirement_violation
struct _Sequence_concept_specification { static void _Sequence_requirement_violation(_Sequence __s) { // Refinement of ForwardContainer _ForwardContainer_concept_specification<_Sequence>::_ForwardContainer_requirement_violation(__s); // Refinement of DefaultConstructible _DefaultConstructible_concept_specification<_Sequence>::_DefaultConstructible_requirement_violation(__s); // Valid Expressions _ERROR_IN_STL_SEQ::__fill_constructor_requirement_violation(__s); _ERROR_IN_STL_SEQ::__fill_default_constructor_requirement_violation(__s); _ERROR_IN_STL_SEQ::__range_constructor_requirement_violation(__s); _ERROR_IN_STL_SEQ::__insert_function_requirement_violation(__s); _ERROR_IN_STL_SEQ::__fill_insert_function_requirement_violation(__s); _ERROR_IN_STL_SEQ::__range_insert_function_requirement_violation(__s); _ERROR_IN_STL_SEQ::__erase_function_requirement_violation(__s); _ERROR_IN_STL_SEQ::__range_erase_function_requirement_violation(__s); _ERROR_IN_STL_SEQ::__front_function_requirement_violation(__s); }
而无论是_BackInsertionSequence_concept_specification还是_Sequence_concept_specification完成Sequence Concept Check都是通过_ERROR_IN_STL_SEQ
中的静态方法完成:给出在_BackInsertionSequence_concept_specification中使用_ERROR_IN_STL_SEQ中的两个静态方法的源码:
template <class _XX> static void __push_back_function_requirement_violation(_XX& __s) { typename _XX::value_type __t = typename _XX::value_type(); __s.push_back(__t); } template <class _XX> static void __pop_back_function_requirement_violation(_XX& __s) { __s.pop_back(); }
贴了这么多的源码,说了思路,还没有分析过一段代码.下面就简单分析一下这段简单的代码.
__push_back_function_requirement_violation静态方法中创建一个对象_t,然后调用传入的类型_s(追溯到前面也就是Stack中的_Sequence)的
push_back方法. 在编译期间,如果在创建_t和调用push_back方法的时候出现错误,都会有警报.
__pop_back_function_requirement_violation方法类似.
而在_BackInsertionSequence_concept_specification中调用了_Sequence_concept_specification中的静态方法,来看看这又做了些什么.
_Sequence_concept_specification中除了调用_ERROR_IN_STL_SEQ中的静态方法检查外,还调用了_ForwardContainer_concept_specification和
_DefaultConstructible_concept_specification中的静态方法,这两个模板类在Container_concepts.h文件中,源码如下:
template <class _ForwardContainer> struct _ForwardContainer_concept_specification { static void _ForwardContainer_requirement_violation(_ForwardContainer __c) { // Refinement of Container _Container_concept_specification<_ForwardContainer>::_Container_requirement_violation(__c); // Requirements on Iterators typedef typename _ForwardContainer::iterator iter; typedef typename _ForwardContainer::const_iterator const_iter; _ForwardIterator_concept_specification<const_iter>::_ForwardIterator_requirement_violation(const_iter()); _Mutable_ForwardIterator_concept_specification<iter>::_Mutable_ForwardIterator_requirement_violation(iter()); } };
(只给出_ForwardContainer_concept_specification的源码.)
而和Sequence Check同样,_ForwardContainer_concept_specification里面也调用了_Container_concept_specification模板中的静态方法,
然后_Container_concept_specification调用_ERROR_IN_STL_CONTAINER中的静态方法执行Container Concept Check.
所以我们直接去看_ERROR_IN_STL_CONTAINER中的静态方法.
template <class _Container> static void __empty_function_must_be_const(const _Container& __c) { __c.empty(); } template <class _Container> static void __empty_function_requirement_violation(_Container& __c) { __c.empty(); __empty_function_must_be_const(__c); } template <class _Container> static void __swap_function_requirement_violation(_Container& __c) { __c.swap(__c); }
分析起来很简单,和上面一样,是对Stack中的参数_Sequence执行一是否存在的方法检查.如果_Sequence中不存在这些方法,那么就会在编译期通不过.
到这里可以说比前面的一篇文章清晰了一点.但是还不够.因为SGI STL不仅仅执行这些检查. 为什么?
我们看看_ForwardContainer_requirement_violation中的源码:
typedef typename _ForwardContainer::iterator iter; typedef typename _ForwardContainer::const_iterator const_iter; _ForwardIterator_concept_specification<const_iter>::_ForwardIterator_requirement_violation(const_iter()); _Mutable_ForwardIterator_concept_specification<iter>::_Mutable_ForwardIterator_requirement_violation(iter())
又调用了另外的模板类中的静态方法. 不怕麻烦,再去看看吧._ForwardIterator_concept_specification源码:
template <class _ForwardIterator> struct _ForwardIterator_concept_specification { static void _ForwardIterator_requirement_violation(_ForwardIterator __i) { // Refinement of InputIterator _InputIterator_concept_specification<_ForwardIterator>:: _InputIterator_requirement_violation(__i); }
可以看到又调用了其他模板类中的静态方法执行检查.....
说实话,少年看到这里有点无语了... SGI STL的检查分层次很多,而且很复杂. 但是继续看下去吧~
最后会发现,执行Iterator和其他琐碎检查的静态方法都是_STL_ERROR提供的.好吧,看过这么多了,都是跳来跳去的.
现在就直接去看_STL_ERROR中的静态方法.
template <class _Type> static _Type __default_constructor_requirement_violation(_Type) { return _Type(); } template <class _Type> static _Type __copy_constructor_requirement_violation(_Type __a) { _Type __c(__a); return __c; }
上面给出了对默认构造函数和拷贝构造函数的检查.
template <class _Iterator> static void __preincrement_operator_requirement_violation(_Iterator __i) { ++__i; } template <class _Iterator> static void __postincrement_operator_requirement_violation(_Iterator __i) { __i++; }
前自增和后自增的检查.
另外,贯穿始终,在所有提供静态方法检测的结构体中都有一个宏__sink_unused_warning,这个宏的存在是为了消除编译器在编译器对未使用变量的警告.
...
省略号,这里真的略去一万字...
好吧,到这里 SGI STL源码种对于在编译期的偏特化检查就介绍完了. 如果介绍的不完整,那么请在评论中给出合理的解释.我会认真看的.
"来日纵使千千阙歌 飘于远方我路上"
"来日纵使千千晚星 亮过今晚月亮"