Nontype Template Parameter(非类型模板参数)
Type parameter(类型参数)之外,我们也可以为 template 使用 nontype parameter(非类型参数)。这样的参数亦被视为 template 类型的一部分。例如对于标准的 class bitset<>,你可以传递bit 个数为实参。例如:
bitset< 32 > flags32 ;// 32bits 的 bitset bitset< 50 > flags50 ;// 50bits 的 bitset
对于上述 bitset 有着不同的类型,因为它们使用不同的 template 实参。因此,不能对上述二者进行赋值或者比较等操作,除非它们之间有一个相应的类型转换。
Default Template Parameter(模板参数默认值)
Class template 可以拥有默认实参。例如下述的声明式,允许我们在声明 class MyClass 对象时指定 1 或 2 个 template 实参;
template < typename T ,typename container = vector> class MyClass;
如果只对 MyClass 传入一个实参,则第二实参会采用默认值,且 template 实参可根据前一个实参为依据而定义。例如
Myclass< int > x1; //实际参数为 MyClass< int , Vector< int> >
关键字 typename
关键字 typename 用来指明紧跟其后的是个类型。例如:
class Q
{
public:
typedef int SubType;
};
template
class MyClass
{
typename T::SubType* ptr;
};
在上述例子中,typename 被用来阐明“ SubType 是一个定义于 class T 中的类型”,因此,ptr 的类型为一个指向 T::SubType类型的指针,即一个 int 型指针。
对于 SubType 也可以是一个抽象类型,例如一个 class :
class Q
{
public:
class SubType;
};
template
class MyClass
{
typename T::SubType* ptr;
};
int main()
{
MyClass z;
return 0;
}
Member Template(成员模板)
class 的成员函数可以是 template。然而 member template 不可以是 virtual。例如
class MyClass
{
template
void f(T);
};
对于上述代码中 M有Class:: f()声明了“一组”成员函数,其参数类型可以是任意类型。你可以通过传递任何实参给它们,只要该实参提供了“ f() 用到的所有操作”。
这一语言特性往往被用来支持 class template 内的成员之间的自动类型转换。例如下列的定义式中,assign() 的实参 x 必须和 value 的类型完全相同。(两个对象的类型相同)
templateclass MyClass { private: T value; public: void assign(const MyClass & x)//x必须有和value相同的类型,即为 *this { value = x.value; } };
如果 assign 的调用者(value)与其实参(x)template 类型不同,是不被允许使用的,即便提供了类型之间的转换。
void f()
{
MyClass d;
MyClass x;
d.assign(d);
d.assign(x);//不存在从 MyClass到const MyClass的转换
}
但是,如果提供一个不一样的 template 类型,你就可以从“必须精确吻合”的规则中解脱。例如下属例子中,这个成员函数的 template 实参可以为任何 template 类型,只要该类型“可被赋值”:
templateclass MyClass { private: T value; public: template void assign(const MyClass & x)//修改处::可以接受任意类型 template 类型参数 { value = x.getValue(); } T getValue()const { return value; } };
则对于之前的操作便是可行的:
void f()
{
MyClass d;
MyClass x;
d.assign(d);
d.assign(x);// d的类型为double
}
特别注意,对于修改之后的模板,assign() 的实参 x ,其类型不同于 *this 的类型,因此我们不能直接取用 MyClass<>的 private 和 protected 成员。如果想使用这些成员,你需要它提供一个函数例如:T getValue() ;
Member template 的一个特殊形式是所谓的 template 构造函数。这种东西通常被提供用于“对象被复制时给予的隐式类型转换”能力。但是对于 template 构造函数并不会压制 copy 构造函数的隐式声明,如果类型完全吻合,则会调用 copy 构造函数。例如,如果含有copy 构造函数
void f()
{
MyClass d;
MyClass x;
d.assign(d); //调用 copy
d.assign(x);// 调用 member template
}



