22-成员模板
14.4.7 成员模板
模板可用作结构、类或模板类的成员。要完全实现STL的设计,必须使用这项特性。程序清单14.20是一个简短的模板类示例,该模板类将另一个模板类和模板函数作为其成员。
程序清单14.20 tempmemb.cpp
// tempmemb.cpp -- template members
#include <iostream>
using std::cout;
using std::endl;
template <typename T>
class beta
{
private:
template <typename V> // nested template class member
class hold
{
private:
V val;
public:
hold(V v = 0) : val(v) {}
void show() const { cout << val << endl; }
V Value() const { return val; }
};
hold<T> q; // template object
hold<int> n; // template object
public:
beta( T t, int i) : q(t), n(i) {}
template<typename U> // template method
U blab(U u, T t) { return (n.Value() + q.Value()) * u / t; }
void Show() const { q.show(); n.show();}
};
int main()
{
beta<double> guy(3.5, 3);
cout << "T was set to double\n";
guy.Show();
cout << "V was set to T, which is double, then V was set to int\n";
cout << guy.blab(10, 2.3) << endl;
cout << "U was set to int\n";
cout << guy.blab(10.0, 2.3) << endl;
cout << "U was set to double\n";
cout << "Done\n";
return 0;
}
在程序清单14.20中,hold模板是在私有部分声明的,因此只能在beta类中访问它。beta类使用hold模板声明了两个数据成员:
hold<T> q; // template object
hold<int> n; // template object
n是基于int类型的hold对象,而q成员是基于T类型(beta模板参数)的hold对象。在main()中,下述声明使得T表示的是double,因此q的类型为hold
beta<double> guy(3.5, 3);
blab()方法的U类型由该方法被调用时的参数值显式确定,T类型由对象的实例化类型确定。在这个例子中,guy的声明将T的类型设置为double,而下述方法调用的第一个参数将U的类型设置为int(参数10对应的类型):
cout << guy.blab(10, 2.5) << endl;
因此,虽然混合类型引起的自动类型转换导致blab()中的计算以double类型进行,但返回值的类型为U(即int),因此它被截断为28,如下面的程序输出所示:
T was set to double
3.5
3
V was set to T, which is double, then V was set to int
28
U was set to int
28.2609
U was set to double
Done
注意到调用guy.blab()时,使用10.0代替了10,因此U被设置为double,这使得返回类型为double,因此输出为28.2608。
正如前面指出的,guy对象的声明将第二个参数的类型设置为double。与第一个参数不同的是,第二个参数的类型不是由函数调用设置的。例如,下面的语句仍将blah()实现为blah(int, double),并根据常规函数原型规则将3转换为类型double:
cout << guy.blab(10, 3) << endl;
可以在beta模板中声明hold类和blah方法,并在beta模板的外面定义它们。然而,很老的编译器根本不接受模板成员,而另一些编译器接受模板成员(如程序清单14.20所示),但不接受类外面的定义。然而,如果所用的编译器接受类外面的定义,则在beta模板之外定义模板方法的代码如下:
template <typename T>
class beta
{
private:
template <typename V> // declaration
class hold;
hold<T> q;
hold<int> n;
public:
beta( T t, int i) : q(t), n(i) {}
template<typename U> // declaration
U blab(U u, T t);
void Show() const { q.show(); n.show();}
};
// member definition
template <typename T>
template<typename V>
class beta<T>::hold
{
private:
V val;
public:
hold(V v = 0) : val(v) {}
void show() const { std::cout << val << std::endl; }
V Value() const { return val; }
};
// member definition
template <typename T>
template <typename U>
U beta<T>::blab(U u, T t)
{
return (n.Value() + q.Value()) * u / t;
}
上述定义将T、V和U用作模板参数。因为模板是嵌套的,因此必须使用下面的语法:
template <typename T>
template <typename V>
而不能使用下面的语法:
template<typename T, typename V>
定义还必须指出hold和blab是beta