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

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

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

     

     

     

      

     

     

      

      

     
  • 相关阅读:
    Spring AOP入门基础-继承、装饰者,代理的选择
    Java Ajax入门
    Servlet Config和Context入门
    MapReduce的Shuffle理解
    Servlet Response常用方法
    Servlet Request常用方法
    HDFS中block设置128M的原因
    【Java】java获取json中某个字段
    【Java】字符串转json
    【Linux】shell脚本参数传递
  • 原文地址:https://www.cnblogs.com/respawn/p/2611118.html
Copyright © 2020-2023  润新知