当前位置:嗨网首页>书籍在线阅读

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类的成员,这是通过使用作用域解析运算符来完成的。