C++ Standard Stl -- SGI STL源码学习笔记(03) STL中的模板编译期检查与偏特化编译期检查
2012-07-27 10:13 respawn 阅读(1672) 评论(0) 收藏 举报前一篇文章中说了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源码种对于在编译期的偏特化检查就介绍完了. 如果介绍的不完整,那么请在评论中给出合理的解释.我会认真看的.
"来日纵使千千阙歌 飘于远方我路上"
"来日纵使千千晚星 亮过今晚月亮"
浙公网安备 33010602011771号