C++ Standard Stl SGI STL源码学习笔记(03) STL中的模板编译期检查与偏特化编译期检查

  前一篇文章中说了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源码种对于在编译期的偏特化检查就介绍完了. 如果介绍的不完整,那么请在评论中给出合理的解释.我会认真看的.

"来日纵使千千阙歌 飘于远方我路上"

"来日纵使千千晚星 亮过今晚月亮"  

 

 

 

  

 

 

  

  

 
原文地址:https://www.cnblogs.com/respawn/p/2611118.html