template模板三

来源:互联网 发布:人工智能基金如何买 编辑:程序博客网 时间:2024/05/14 14:04

三、模板的形参


有三种类型的模板形参:类型形参,非类型形参和模板形参。

  1、类型形参

    1.1 、类型模板形参:类型形参由关见字class或typename后接说明符构成,如template<class T> void h(T a){};其中T就是一个类型形参,类型形参的名字由用户自已确定。模板形参表示的是一个未知的类型。模板类型形参可作为类型说明符用在模板中的任何地方,与内置类型说明符或类类型说明符的使用方式完全相同,即可以用于指定返回类型,变量声明等。

    作者原版:1.2、 不能为同一个模板类型形参指定两种不同的类型,比如template<class T>void h(T a, T b){},语句调用h(2, 3.2)将出错,因为该语句给同一模板形参T指定了两种类型,第一个实参2把模板形参T指定为int,而第二个实参3.2把模板形参指定为double,两种类型的形参不一致,会出错。(针对函数模板)

    作者原版:1.2针对函数模板是正确的,但是忽略了类模板。下面将对类模板的情况进行补充。

    本人添加1.2补充版(针对于类模板)、当我们声明类对象为:A<int> a,比如template<class T>T g(T a, T b){},语句调用a.g(2, 3.2)在编译时不会出错,但会有警告,因为在声明类对象的时候已经将T转换为int类型,而第二个实参3.2把模板形参指定为double,在运行时,会对3.2进行强制类型转换为3。当我们声明类的对象为:A<double> a,此时就不会有上述的警告,因为从intdouble是自动类型转换。

2、非类型形参

    2.1 、非类型模板形参:模板的非类型形参也就是内置类型形参,如template<class T, int a> class B{};其中int a就是非类型的模板形参。

    2.2、 非类型形参在模板定义的内部是常量值,也就是说非类型形参在模板的内部是常量。

    2.3、 非类型模板的形参只能是整型,指针和引用,像double,String, String **这样的类型是不允许的。但是double &,double *,对象的引用或指针是正确的。

    2.4、 调用非类型模板形参的实参必须是一个常量表达式,即他必须能在编译时计算出结果。

    2.5 、注意:任何局部对象,局部变量,局部对象的地址,局部变量的地址都不是一个常量表达式,都不能用作非类型模板形参的实参。全局指针类型,全局变量,全局对象也不是一个常量表达式,不能用作非类型模板形参的实参。

    2.6、 全局变量的地址或引用,全局对象的地址或引用const类型变量是常量表达式,可以用作非类型模板形参的实参

    2.7 、sizeof表达式的结果是一个常量表达式,也能用作非类型模板形参的实参。

    2.8 、当模板的形参是整型时调用该模板时的实参必须是整型的,且在编译期间是常量,比如template <class T, int a> class A{};如果有int b,这时A<int, b> m;将出错,因为b不是常量,如果const int b,这时A<int, b> m;就是正确的,因为这时b是常量。

    2.9 、非类型形参一般不应用于函数模板中,比如有函数模板template<class T, int a> void h(T b){},若使用h(2)调用会出现无法为非类型形参a推演出参数的错误,对这种模板函数可以用显示模板实参来解决,如用h<int, 3>(2)这样就把非类型形参a设置为整数3。显示模板实参在后面介绍。

    2.10、 非类型模板形参的形参和实参间所允许的转换
      1、允许从数组到指针,从函数到指针的转换。如:template <int *a> class A{}; int b[1]; A<b> m;即数组到指针的转换
      2、const修饰符的转换。如:template<const int *a> class A{}; int b; A<&b> m;   即从int *到const int *的转换。
      3、提升转换。如:template<int a> class A{}; const short b=2; A<b> m; 即从short到int 的提升转换
      4、整值转换。如:template<unsigned int a> class A{};   A<3> m; 即从int 到unsigned int的转换。
      5、常规转换。

/* ///////////////////////////////////////////////////////////////////// *//*!   @file    tripletpl.hxx  @author  night wing  @date    2017/03  @brief   The file declare the TripleTpl Template  @par     History  @verbatim          <author>   <time>   <version>  <desc>                                            chen   2016/11   0.1.0     build this module         chen   2017/01   0.2.0     add. func         chen   2017/03   0.3.0     add. TripleTpl( ) constructor with paramters         chen   2017/03   0.4.0     add. lastReadable( ) API  @endverbatim*//* ///////////////////////////////////////////////////////////////////// */#ifndef  __SCIPACK_TRIPLETPL_HXX#define  __SCIPACK_TRIPLETPL_HXX/*!  @addtogroup  SciPack  @{*//*!  @addtogroup  devel    @{*//*!  @addtogroup  devel_Exported_Classes  @{*//* /////////////////////////////////////////////////////////////////////   config   ///////////////////////////////////////////////////////////////////// */#if !defined( SCIPACK_HIDDEN )#if defined( _WIN32 ) || defined( __CYGWIN__ )  #define SCIPACK_HIDDEN#else  #if __GNUC__ >= 4     #define SCIPACK_HIDDEN __attribute__ ((visibility ("hidden")))  #else     #define SCIPACK_HIDDEN  #endif#endif#endif#ifndef SCIPACK_NAMESPACE_BEGIN#define SCIPACK_NAMESPACE_BEGIN  namespace SciPack {#define SCIPACK_NAMESPACE_END    }#endif#ifndef SCIPACK_CLASS#define SCIPACK_CLASS( c )  SciPack::##c#endif#ifndef SCIPACK_CLASS_PTR#define SCIPACK_CLASS_PTR( c, obj )  (( SciPack::##c *)( obj ))#endif// ///////////////////////////////////////////////////////////////////////  definition & include// ///////////////////////////////////////////////////////////////////// #include <stdint.h>#include <atomic>    // C++11SCIPACK_NAMESPACE_BEGIN// ///////////////////////////////////////////////////////////////////////! Triple Template ( three object swap between two threads ) /*!  this class is used for define the template of the user structure \n*/// ///////////////////////////////////////////////////////////////////// template <typename T > class  TripleTpl {public:    // ======================================================    // CTOR    // ======================================================    TripleTpl (  );    TripleTpl ( T member_a, T member_b, T member_c );    virtual ~TripleTpl(  );    // ======================================================    // Functions    // ======================================================    T *   writable(  );    void  swap( bool is_data_on = true, bool *is_old_data_picked = 0 );        const T *   readable ( );    const T *   lastReadable( ) { return & m_data[ m_out_idx ]; }    bool  isDataOn(  );    void  writeValue( const T &v );    T &   readValue (      );      private:    // ====================================================    // local var.    // ====================================================    int    m_in_idx, m_out_idx;    std::atomic<int>  m_tmp_idx;    T      m_data[3];    private: TripleTpl ( const TripleTpl & ); TripleTpl & operator=( const TripleTpl & ); // disable copy and assign};// ///////////////////////////////////////////////////////////////////// the template implement functions// ///////////////////////////////////////////////////////////////////template <typename T >     TripleTpl<T> ::  TripleTpl (  ) { m_in_idx = 0; m_out_idx = 2; m_tmp_idx.store(1); }template <typename T >    TripleTpl<T> ::  TripleTpl ( T member_a, T member_b, T member_c ) {    m_in_idx = 0; m_out_idx = 2; m_tmp_idx.store(1);     m_data[0] = member_a; m_data[1] = member_b; m_data[2] = member_c;}template <typename T >    TripleTpl<T> :: ~TripleTpl (  ) {  }template <typename T >T *  TripleTpl<T> :: writable (  ) { return &m_data[ m_in_idx ]; }template <typename T >void TripleTpl<T> :: swap ( bool is_data_on, bool *is_old_data_picked ){    int tmp_idx; int flag = ( is_data_on ? 0x80 : 0x00 );    do {         tmp_idx = m_tmp_idx.load( );        if ( m_tmp_idx.compare_exchange_strong( tmp_idx, m_in_idx | flag )) {             m_in_idx = tmp_idx & 0x7f;            break;        }    } while ( true );        if ( is_old_data_picked != 0 ) { *is_old_data_picked = ( tmp_idx & 0x80 ? false : true ); } }template <typename T >bool      TripleTpl<T> :: isDataOn ( ) { int tmp_idx = m_tmp_idx.load( ); return ( tmp_idx & 0x80 ? true : false ); }template <typename T >const T*  TripleTpl<T> :: readable (  ){    int tmp_idx;     do {        tmp_idx = m_tmp_idx.load( );        if ( m_tmp_idx.compare_exchange_strong( tmp_idx, m_out_idx )) {            m_out_idx = ( tmp_idx & 0x7f ); if ( m_out_idx > 2 ) { m_out_idx = 0; }             break;        }    } while ( true );    return ( tmp_idx & 0x80 ? & m_data[ m_out_idx ] : nullptr );}template <typename T >void     TripleTpl<T> :: writeValue( const T &v ){    T *w = this->writable( );    *w = v;    this->swap( true, NULL );}template <typename T >T &      TripleTpl<T> :: readValue (  )   {    if ( this->isDataOn( )) { this->readable( ); } // update if necessary.    return m_data[ m_out_idx ];}SCIPACK_NAMESPACE_END/*!  @}*//*!  @}*//*!  @}*/#endif