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

18-显式具体化

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

8.5.3 显式具体化

假设定义了如下结构:

struct job
{
      char name[40];
      double salary;
      int floor;
};

另外,假设希望能够交换两个这种结构的内容。原来的模板使用下面的代码来完成交换:

temp = a;
a = b;
b = temp;

由于C++允许将一个结构赋给另一个结构,因此即使T是一个job结构,上述代码也适用。然而,假设只想交换salary和floor成员,而不交换name成员,则需要使用不同的代码,但Swap()的参数将保持不变(两个job结构的引用),因此无法使用模板重载来提供其他的代码。

然而,可以提供一个具体化函数定义——称为显式具体化(explicit specialization),其中包含所需的代码。当编译器找到与函数调用匹配的具体化定义时,将使用该定义,而不再寻找模板。

具体化机制随着C++的演变而不断变化。下面介绍C++标准定义的形式。

1.第三代具体化(ISO/ANSI C++标准)

试验其他具体化方法后,C++98标准选择了下面的方法。

  • 对于给定的函数名,可以有非模板函数、模板函数和显式具体化模板函数以及它们的重载版本。
  • 显式具体化的原型和定义应以template<>打头,并通过名称来指出类型。
  • 具体化优先于常规模板,而非模板函数优先于具体化和常规模板。

下面是用于交换job结构的非模板函数、模板函数和具体化的原型:

// non template function prototype
void Swap(job &, job &);
// template prototype
template <typename T>
void Swap(T &, T &);
// explicit specialization for the job type
template <> void Swap<job>(job &, job &);

正如前面指出的,如果有多个原型,则编译器在选择原型时,非模板版本优先于显式具体化和模板版本,而显式具体化优先于使用模板生成的版本。例如,在下面的代码中,第一次调用Swap()时使用通用版本,而第二次调用使用基于job类型的显式具体化版本。

...
template <class T>    // template
void Swap(T &, T &);
// explicit specialization for the job type
template <> void Swap<job>(job &, job &);
int main()
{
    double u, v;
    ...
    Swap(u,v);   // use template
    job a, b;
    ...
    Swap(a,b);   // use void Swap<job>(job &, job &)
}

Swap中的是可选的,因为函数的参数类型表明,这是job的一个具体化。因此,该原型也可以这样编写:

template <> void Swap(job &, job &); // simpler form

下面来看一看显式具体化的工作方式。

2.显式具体化示例

程序清单8.13演示了显式具体化的工作方式。

程序清单8.13 twoswap.cpp

// twoswap.cpp -- specialization overrides a template
#include <iostream>
template <typename T>
void Swap(T &a, T &b);
struct job
{
    char name[40];
    double salary;
    int floor;
};
// explicit specialization
template <> void Swap<job>(job &j1, job &j2);
void Show(job &j);
int main()
{
    using namespace std;
    cout.precision(2);
    cout.setf(ios::fixed, ios::floatfield);
    int i = 10, j = 20;
    cout << "i, j = " << i << ", " << j << ".\n";
    cout << "Using compiler-generated int swapper:\n";
    Swap(i,j); // generates void Swap(int &, int &)
    cout << "Now i, j = " << i << ", " << j << ".\n";
    job sue = {"Susan Yaffee", 73000.60, 7};
    job sidney = {"Sidney Taffee", 78060.72, 9};
    cout << "Before job swapping:\n";
    Show(sue);
    Show(sidney);
    Swap(sue, sidney); // uses void Swap(job &, job &)
    cout << "After job swapping:\n";
    Show(sue);
    Show(sidney);
    // cin.get();
    return 0;
}
template <typename T>
void Swap(T &a, T &b) // general version
{
    T temp;
    temp = a;
    a = b;
    b = temp;
}
// swaps just the salary and floor fields of a job structure
template <> void Swap<job>(job &j1, job &j2) // specialization
{
    double t1;
    int t2;
    t1 = j1.salary;
    j1.salary = j2.salary;
    j2.salary = t1;
    t2 = j1.floor;
    j1.floor = j2.floor;
    j2.floor = t2;
}
void Show(job &j)
{
    using namespace std;
    cout << j.name << ": $" << j.salary
         << " on floor " << j.floor << endl;
}

下面是该程序的输出:

i, j = 10, 20.
Using compiler-generated int swapper:
Now i, j = 20, 10.
Before job swapping:
Susan Yaffee: $73000.60 on floor 7
Sidney Taffee: $78060.72 on floor 9
After job swapping:
Susan Yaffee: $78060.72 on floor 9
Sidney Taffee: $73000.60 on floor 7