C++泛型设计 - 模板规格(译)
C++关键字template可以用来声明一批参数化的类(模板类)或函数(模板函数)。
一般使用格式如下:
template < template-parameter-list > declaration
说明
template-parameter-list是一个以逗号分隔开的模板参数。这些模板参数可能是一些类型(以这种格式:class identifier,typename identifier或是template<template-parameter-list> class identifier)或是一些非类型的参数,它们常用于模板体内,代表着实际使用时指定的类型或是非类型的对象。模板参数的语法如下之一:
parameter-declaration
² class identifier [ = typename ]
² typename identifier [ = typename ]
² template < template-parameter-list > class [identifier][= name]
你可以像实例化一个普通类一样去实例化一个类模板多次,但你必须以一对尖括号(<>)来包含模板参数。这些模板参数可以是任意类型(template-parameter-list包含class或是typename关键字)或是一个适当类型的值(template-parameter-list包含非类型的参数)。调用一个模板函数没有特定的语法,尽管尖括号和模板参数是必需的(当模板参数不能由参数到函数引出时)。
如下所示,template-parameter-list的几个部分都是不同的,这些参数主要用于在模板类中的函数。
template< class T, int i > class MyStack...
在这个例子中,这个模板可以接爱一个类型(class T)和一个常量参数(int i)。上面这个例子的模板将使用类型T和常量的整数i。在MyStack声明的类体中,你必须引用到这个标识符T。
一个模板的声明不会产生代码,它仅阐释一个类或函数的组织,当它被其它代码引用时才会产生。
模板可以在全局或是名字空间及类域下进行声明,但不能在一个函数内声明。
下面这个例子演示了一个类模板以一个类型T及一个非类型模板参数i进行的声明、定义及实例化:
实例
// template_specifications1.cpp
// Template Class Usage 1: The T is Type, and the i is constant value of Integer
template <class T, int i>
class TestClass
{
public:
char buffer[i];
T testFunc( T* p1 );
};
template <class T, int i>
T TestClass<T, i>::testFunc(T* p1)
{
return *(p1++);
}
// To create an instance of TestClass
TestClass<char, 5> ClassInst;
int main()
{}
// template_specifications2.cpp
class Y
{};
// Template Class Usage 2: The pT is Value of Pointer
template <class T, T* pT>
class X1
{};
// Template Class Usage 3: The T2 is optional Default Parameter
template <class T1, class T2 = T1>
class X2
{};
// To create those instances of upon classes
Y aY;
X1<Y, &aY> x1;
X2<int> x2;
int main()
{}
// template_specifications3.cpp
#include <stdio.h>
// Template Structure Usage 1: Normal
template <class T>
struct str1
{
T t;
};
// Template Structure Usage 2:The Type of T can be a template class
template <template<class A> class T>
struct str2
{
T<int> t;
};
int main()
{
str2<str1> mystr2;
mystr2.t.t = 5;
printf_s( “%d/n”, mystr2.t.t );
}
/* ---------------------- */
输出
5
// references__supported_as_nontype_template_parameters.cpp
#include <stdio.h>
extern “C” int printf( const char*, ... );
template <int& ri>
struct S
{
// constructor method
S()
{
printf( “ ri is %d/n”, ri );
}
// destructor method
~S()
{
printf( “ri is %d/n”, ri );
}
};
int i = 1;
int main()
{
S<i> s;
i = 0;
}
/* ---------------------- */
输出
ri is 1
ri is 0
非类型的模板参数
非类型的模板参数必须是:整数/枚举/指针/引用/指向一个成员类型的指针(例如template_specifications2.cpp的X1模板类)。正如const或volatile类型一样,在编译时刻它们是不可改变的。另外,float类型的指针不能用作模板参数。尽管一个指向 “类对象/结构/union类型”的指针可用作模板参数,但是它们本身却不可用作模板参数。若传递的是数组名称,就被转化为指针看待。若传递的是函数名称,当然,是被看作为函数指针。字符串是不允许看作为模板参数的。
在一个模板声明中使用typename
在模板参数列表中,可以使用typename关键字来定义一个参数。例如下面的模板声明是一样的:
template <class T1, class T2> class X...
template <typename T1, typename T2> class X...
缺省的模板参数
类模板可以拥有缺省参数(指定使用赋值操作符赋一个缺省的类型或是一个值)。确记,函数模板不可有缺省参数。
/* 类模板缺省参数用法参考简单例子 */
template<typename Type>
class allocator
{};
template<typename Type, typename Allocator = allocator<Type>>
class stack
{};
stack<int> MyStack;
模板参数的复用
在模板参数列表中,模板参数可以复用。如template_specifications2.cpp例子中的X1模板类的模板参数T在第二个参数中获得到复用。
模板的模板参数
模板参数也可以进行模板化。这个创立前提条件是,参数本身必须是一个模板,非一个由模板构造好的类。在下面的例子中,模板参数的名称A对于一个模板的模板参数来说,可以省略,因为没有被使用。
引用模板参数
Visual Studio .NET 2003引入了一个新特性,可以引用非类型的模板参数。这个方法在以前的版本中是不允许的。
—完—