现在的位置: 首页 > 综合 > 正文

ISO/IEC14882:2003之条款14.1——模板形参

2012年09月12日 ⁄ 综合 ⁄ 共 4265字 ⁄ 字号 评论关闭

14.1 模板形参

1、template-parameter的语法是:

        template-parameter:
                type-parameter

                parameter-declaration

        type-parameter:

                   class identifieropt
                   class identifieropt = type-id
                   typename identifieropt

                   typename identifieropt = type-id

                   template < template-parameter-list > class identifieropt

                   template < template-parameter-list > class identifieropt = id-expression

2、在一个template-parameter中,class和typename之间没有语义上的不同。typename后面跟着一个unqualified-id命名了一个模板类型形参。typename后面跟着一个qualified-id指示在一个非类型parameter-declaration中的类型[注:由于模板的template-parameter以及模板的template-argument被对待为说明性目的的类型,因此术语非类型形参以及非类型实参被用于引用为非类型、非模板形参和实参]。一个存储类不应该在一个template-parameter声明中指定。[注:一个模板形参可以是一个类模板。比如:

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

template
<class K, class V, template <class T> class C = myarray>
class Map {
C
<K> key;
C
<V> value;
};

——注结束]。

[译者注:对于这里的模板类型形参和非类型形参,我将举一个例子来说明:

struct A
{
typedef
int TYPE;
};

// T is unqualified, T::TYPE is qualified
template <typename T, typename T::TYPE>
struct B
{

};

extern "C" void cpp_test(void)
{
B
<A, 100>();
}

3、 在模板声明的作用域中,一个type-parameter定义了其identifier是一个type-name(如果用class或typename声明)或template-name(如果用template声明)。[注:因为名字查找规则,一个可以被解释为一个非类型template-parameter或一个type-parameter(因为其identifier是一个已经存在的类的名字)的template-parameter被采取为一个type-parameter。比如:

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

template
<class T, T i> void f(T t)
{
T t1
= i; // template-parameter T以及i
::T t2 = ::i; // 全局名字空间成员T以及i
}

这里,模板f具有一个称为T的type-parameter,而不是一个未命名的非类型的类T的template-parameter。]

4、 一个非类型的template-parameter应该具有下列(可选地cv限定)类型:

      ——整型或枚举类型,

      ——指向对象的指针或指向函数的指针,

      ——对对象的引用或对函数的引用,

      ——指向成员的指针。

5、[注:其它类型是被禁止的,要么是下面显式地禁止,要么是被支配template-argument的形式的规则隐式地禁止(14.3)。]template-parameter上的顶层cv-qualifier被忽略,当判定其类型时。[译者注:

// 这里,const是顶层,因此被忽略
template <int * const P>
void funcA(void)
{
++*P;
}

// 这里,const不是顶层,因此不能被忽略
template <int const *P>
void funcB(void)
{

}

int a = 10;

extern "C" void cpp_test(void)
{
funcA
<&a>();

funcB
<&a>();
}

6、一个非类型非引用的template-parameter并不是一个左值。它不应该被赋值也不能在任何其它方式下让它的值受到更改。一个非类型非引用的template-parameter不能将其地址被获取。当一个非类型非引用的template-parameter被用作为一个引用的初始化器时,总要使用一个临时变量。[例如:

template <const X& x, int i> void f()
{
i
++; // error: 对模板形参值的修改
&x; // OK
&i; // error: 非引用模板形参的地址
int& ri = i; // error: 非const引用绑定到临时变量
const int& cri = i; // OK: const引用绑定到临时变量
}

——例结束]

7、一个非类型的template-parameter不应该被声明具有浮点、类、或void类型。[例:

template <double d> class X;    // error
template <double* pd> class Y; // OK
template <double& rd> class Z; // OK

——例结束]

8、一个“T的数组”或“返回T的函数”类型的非类型template-parameter被分别调整为“指向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 由于模板形参调整以及隐式的实参转换

——例结束]

9、一个默认的template-parameter是在一个template-parameter中的=之后的一个template-argument(14.3)。一个默认的template-argument可以对任何一种template-parameter(类型,非类型,模板)被指定。一个默认的template-argument可以在一个类模板声明或是一个类模板定义中被指定。一个默认的template-argument不应该在一个函数模板声明或一个函数模板定义中被指定,也不该在一个类模板的一个成员定义的template-parameter-list中被指定。一个默认的template-argument也不该在一个友元模板声明中被指定。[译者注:比如:

template <typename T = int>     // OK
struct A
{
template
<typename Q = T> // OK in GCC
struct B
{

};

template
<typename R = int> // OK in GCC
friend class C;

private:

T var;
};

template
<typename T>
class C
{
private:

T var;

public:

C(
const A<T>& a)
{
var
= a.var;
}
};

template
<typename T = int> // error: 函数模板中不能使用默认模板实参
void func(void)
{

}


extern "C" void cpp_test(void)
{
A
<>::B<>();
C
<>(A<>());
}

10、与一个模板声明或定义一起可使用的默认的template-argument集合,通过将根据定义的默认实参(如果在作用域中)与作用域中的所有声明,如同默认函数实参相同的方式(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-parameter具有一个默认的template-argument,那么所有后面的template-parameter应该提供一个默认的template-argument。[例:

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

——例结束]

12、一个template-parameter不应该通过在同一作用域中的两个不同的声明来给予默认实参。[例:

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

——例结束]

13、一个template-parameter的作用域从其声明点一直延伸到其模板的结束。特别地,一个template-parameter可以被用在后续的template-parameter以及其默认的实参的声明中。[例:

template <class T, T* p, class U = T> class X { /* ... */ };
template
<class T> void f(T* p = new T);

——例结束]

14、一个template-parameter不应该被用在其自己默认的实参中。[译者注:比如:

template <class T>
struct A
{
typedef T TYPE;
};

template
<typename T, typename Q = class A<T>::TYPE> // OK
struct C { };

template
<typename T = class A<T>::TYPE> // error
struct D { };

15、当为一个非类型的template-parameter解析一个默认的template-argument时,第一个非嵌套的>被采取为的template-parameter-list结束,而不是一个大于操作符。[例:

template <int i = 3 > 4 >    // 语法错误
class X { /* ... };

template <int i = (3 > 4) > // OK
class Y { /* ...
*/ };

——例结束]

抱歉!评论已关闭.