如何读取模板部分专门化

How to read the template partial specialization?

本文关键字:板部 专门化 读取 何读取      更新时间:2023-10-16

假设如下声明:

template <typename T> struct MyTemplate;

以下部分专门化的定义似乎使用相同的字母T来指代不同的类型。

template <typename T> struct MyTemplate<T*> {};

例如,让我们举一个具体的实例:

MyTemplate<int *> c;
现在,再次考虑上述部分专门化的定义:
template <typename T> struct MyTemplate<T*> {};

本行第一部分(即template <typename T>), Tint *。在该行的第二部分(即MyTemplate<T*>), Tint !

那么,部分专门化的定义是如何理解的呢?

这样读:

  1. 主模板说明" MyTemplate是一个只有一个类型参数的类模板":

    template <typename> struct MyTemplate;
    
  2. 局部专门化表示,"只要存在类型T "…

    template <typename T>
    

    …因此,T * "…

    类型需要MyTemplate的专门化。
    struct MyTemplate<T *>
    

  3. 您还可以定义显式专门化。例如,可以说"每当为类型X请求专门化时,请使用以下替代定义:

    template <> struct MyTemplate<X> { /* ... */ };
    

注意,类模板的显式特化定义类型,而部分特化定义模板。

从另一个角度来看:部分类模板专门化推导出模式匹配的类模板参数的结构:
template <typename T> struct MyTemplate<T *>
//       ^^^^^^^^^^^^                  ^^^^^
//       This is a new template        Argument passed to the original class
//                                     template parameter

这个新模板的形参名在结构上与原类模板的形参的实参进行匹配。

例子:

  • MyTemplate<void>:类模板的类型参数为void,主模板用于此特化

  • MyTemplate<int *>:类型参数为int *。存在类型T,即T = int,因此请求的类型参数是T *,因此模板的部分专门化定义用于此专门化。

  • MyTemplate<X>:参数类型为X,并且为该参数类型定义了显式专门化,因此使用

专门化的正确阅读如下:

template <typename T> // a *type pattern* with a *free variable* `T` follows
struct MyTemplate<T*> // `T*` is the pattern

当模板由MyTemplate<int*>实例化时,参数是与模式匹配的,而不是类型变量列表。然后从匹配中推导出类型变量的值

要更直接地看到这一点,考虑一个有两个参数的模板。
template <typename T1, typename T2>
struct A;

及其专门化

template <typename T1, typename T2>
struct A<T1*, T2*>;

现在你可以把后者写成

template <typename T2, typename T1>
struct A<T1*, T2*>;

(变量列表顺序颠倒),这与前一个相同。事实上,列表的顺序是无关紧要的。当你调用A<int*, double*>时,可以推断出T1=int, T2=double,无论模板头中T1和T2的顺序如何。

更进一步,你可以这样做

template <typename T>
struct A<T*, T*>;

并在A<int*, int*>中使用它。现在很清楚,类型变量列表与实际的模板形参列表没有直接对应关系。

注意:术语"模式"、"类型变量"、"类型模式匹配"不是标准的c++术语。

你有这样一行:

MyTemplate<int *> c;

你的困惑似乎来自于假设< >中的int *以某种方式对应于template <typename T>中的T。但事实并非如此。在部分特化中(实际上在每个模板声明中),模板参数名只是"自由变量"(或者可能是"占位符")名称。模板参数(在您的例子中是int *)不直接对应于这些,它们对应于模板名称后面的< >中(或将是)的内容。

这意味着实例化的<int *>部分映射到部分专门化的<T*>部分。T只是template <typename T>前缀引入的一个名称。在整个过程中,Tint

没有矛盾。T应该读作T, T*就是T*。

template <typename T> struct MyTemplate<T*> {};

"在这一行的第一部分(即template <typename T>), T是int *。"

No -在template <typename T>中T是整型,在struct MyTemplate<T*> {};中T也是整型。

"注意,当使用部分专门化时,模板参数是从专门化模式推导出来的;template形参不仅仅是实际的模板实参。特别地,对于Vector<Shape*>, T是Shape而不是Shape*。(Stroustrup c++,第4版,25.3,p. 732.)