如何阅读模板偏特化?

How to read the template partial specialization?

假设如下声明:

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

那么,偏特化的定义是怎么读的呢?

你有这条线:

MyTemplate<int *> c;

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

这意味着实例化的 <int *> 部分映射到偏特化的 <T*> 部分。 T 只是由 template <typename T> 前缀引入的名称。整个过程中,T就是int

这样读:

  1. 主模板说“MyTemplate是一个class具有一个类型参数的模板”:

    template <typename> struct MyTemplate;
    
  2. 部分专业化说,"whenever there exists a type T"...

    template <typename T>
    

    ... 这样就要求 MyTemplate 类型的特化 T *"...

    struct MyTemplate<T *>
    

    ...然后使用模板的替代定义。

  3. 您还可以定义明确的专业化。例如,可以说“每当请求类型 X 的特化时,使用此替代定义:

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

请注意,class 模板的显式特化定义了类型,而偏特化定义了模板。

换个角度看:部分class模板特化推导,或模式匹配,结构class 模板参数:

template <typename T> struct MyTemplate<T *>
//       ^^^^^^^^^^^^                  ^^^^^
//       This is a new template        Argument passed to the original class
//                                     template parameter

这个新模板的参数名称在结构上与原始 class 模板参数的参数匹配。

示例:

  • MyTemplate<void>:class模板的类型参数为void,本次特化使用主模板

  • MyTemplate<int *>:类型参数为int *。存在一个类型T,即T = int,使得请求的类型参数为T *,所以这个特化使用模板偏特化的定义[=29] =]

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

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

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

"In the first part of this line (i.e. template <typename T>), T is int *."

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

"Note that when a partial specialization is used, a template parameter is deduced from the specialization pattern; the template parameter is not simply the actual template argument. In particular, for Vector<Shape*>, T is Shape and not Shape*."(Stroustrup C++,第 4 版,25.3,第 732 页。)

专业的正确读法如下:

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=intT2=double,而不管模板头中 T1 和 T2 的顺序如何。

此外,您还可以这样做

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

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

注意:术语 "pattern"、"type variable"、"type pattern matching" 不是标准的 C++ 术语。不过,它们几乎在其他任何地方都是标准的。