C++标准ISO-IEC-14882-2003:第14章:模板-第1节:模板的参数

    技术2022-05-11  14

    14.1 模板的参数

    1.       模板参数的语法是:

    模板参数:

            类型参数

            参数声明

    类型参数:

            class 标识符 opt

            class 标识符 opt = 类型 id

            typename 标识符 opt

            typename 标识符 opt = 类型 id

            template < 模板参数列表 > class 标识符 opt

            template < 模板参数列表 > class 标识符 opt = id 表达式

     

    2.       在模板参数中, class typename 关键字没有语义上的区别。 typename 后面跟一个未限定的 id 命名了一个模板类型参数。 typename 后面跟一个限定的 id 表示非类型参数声明中的类型。模板参数声明中不能指定存储类型。【注:模板参数有可能是类模板,例如:

    template<class T> class myarray { /* ... */ };

    template<class K, class V, template<class T> class C = myarray>

    class Map {

    C<K> key;

    C<V> value;

    // ...

    };

    3.       模板声明的作用域中,类型参数将标识符定义为一个类型名(如果用 class typename 关键字声明),或者将其定义为一个模板名(如果用 template 关键字声明)。【注:按照名字查找规则,模板参数既可以解释为非类型模板参数,又可以解释为类型参数(其标识符是已经存在的一个类的名字),这种情况下,模板参数总是被解释为类型参数。例如:

    class T { /* ... */ };

    int i;

    template<class T, T i> void f(T t)

    {

    T t1 = i; // 参数类型 T i

    ::T t2 = ::i; // 全局名字空间中的 T i

    }

        这里,模板 f 有个类型参数 T ,而非无名的类型为 T 的非类型参数。】

    4.       非类型模板参数必须有如下的类型(可以为 cv- 修饰过的):

    a)       整型或枚举型

    b)      对象指针或函数指针

    c)       对象引用或函数引用

    d)      成员指针

    【按:编译器用只4 字节就能表示的类型】

    5.       【注:根据控制模板参数形式的规则,非类型模板参数不允许其他类型,不论是下述的显式形式,还是隐式形式。】在确定模板参数类型的时候,最外层的 cv- 修饰符会被忽略。

    6.       非类型的非引用模板参数不是左值。该参数不能被赋值,也不能以其他方式改变其值。非类型的非引用模板参数不能取地址。当非类型的非引用模板参数被用做一个引用的初值时,总是会产生临时对象。

    【例:

    template<const X& x, int i> void f()

    {

    i++; // 错误 : 试图改变非类型的非引用模板参数的值

    &x; // OK

    &i; // 错误 : 试图取非类型的非引用模板参数的地址

    int& ri = i; // 错误 : 绑定到临时对象上的是个非 const 引用【按:非 const 可能改变 i 的值】

    const int& cri = i; // OK: 绑定到临时对象上的是个 const 引用

    }

    7.       非类型模板参数不能声明为浮点类型、 class void 类型。【例:

    template<double d> class X; // error

    template<double* pd> class Y; // OK

    template<double& rd> class Z; // OK

    8.       类型为“ T 型数组”或类型为“返回类型为 T 的函数”的非类型模板参数会相应地自动调整为“ T 的指针”或“返回类型为 T 的函数指针”。【例如:

    template<int *a> struct R { /* ... */ };

    template<int b[5]> struct S { /* ... */ };

    int p;

    R<&p> w; // OK

    S<&p> x; // OK 类型调整

    int v[5];

    R<v> y; // OK :隐式实参类型转换

    S<v> z; // OK :(对模板 S: S<int[5]> à S<int*> )类型调整和(对 v: int[5] à int* )隐式实参类型转换

    9.       默认模板参数是模板参数中 = 后面的模板实参部分。默认模板参数可以指定为任意类型的模板参数(类型,非类型,模板)。默认模板参数可以在类模板声明或定义中指定。默认模板参数不能在函数模板声明或定义中指定;也不能在类模板的成员函数定义的模板参数列表中指定。默认模板参数不能在友元模板声明中指定。

    10.    可以用作模板声明或定义的默认模板参数的集合,是通过合并其定义(如果在同一个域中)及其在同一个域中的所有声明而得到的;合并的方式与函数的默认参数的合并方式完全相同( 8.3.6 )。【例如:

    template<class T1, class T2 = int> class A;

    template<class T1 = int, class T2> class A;

    等价于:

    template<class T1 = int, class T2 = int> class A;

    11.    如果模板的其中一个参数有默认值,那么后面跟着的所有模板参数都必须有默认值 【按:不论是直接提供还是通过合并得到】 。【例:

    template<class T1 = int, class T2> class B; // error

    12.    模板参数不能在同一个域中的两个不同的声明中同时指定默认参数。 【按:避免默认参数的重定义】【例如:

    template<class T = int> class X;

    template<class T = int> class X { /*... */ }; // error

    13.    模板参数的作用范围是:从它的声明点开始,一直到模板结束。由此得出,模板参数可以用于后续模板参数的声明及其默认参数中。【例如:

    template<class T, T* p, class U = T> class X { /* ... */ };

    template<class T> void f(T* p = new T);

       

    14.    模板参数不能用于自己的默认参数中。

    15.    当处理一个非类型模板参数的默认参数时,第一个非嵌套的 > 符号被当做模板参数列表的结束符,而不是大于号。【例如:

    template<int i = 3 > 4 > // 语法错误

    class X { /* ... */ };

    template<int i = (3 > 4) > // OK ,虽然有 > ,但是嵌套在 ()

    class Y { /* ... */ };

     


    最新回复(0)