如何阅读模板偏特化?
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>
),T
是int *
。在该行的第二部分(即 MyTemplate<T*>
),T
是 int
!
那么,偏特化的定义是怎么读的呢?
你有这条线:
MyTemplate<int *> c;
您的困惑似乎来自假设 < >
中的 int *
以某种方式对应于 template <typename T>
中的 T
。它不是。在部分特化中(实际上在每个模板声明中),模板参数名称只是 "free variable"(或者可能是 "placeholder")名称。模板参数(int *
在你的例子中)不直接对应于这些,它们对应于模板名称后面的 < >
中的(或将是)内容。
这意味着实例化的 <int *>
部分映射到偏特化的 <T*>
部分。 T
只是由 template <typename T>
前缀引入的名称。整个过程中,T
就是int
。
这样读:
主模板说“MyTemplate
是一个class具有一个类型参数的模板”:
template <typename> struct MyTemplate;
部分专业化说,"whenever there exists a type T
"...
template <typename T>
... 这样就要求 MyTemplate
类型的特化 T *
"...
struct MyTemplate<T *>
...然后使用模板的替代定义。
您还可以定义明确的专业化。例如,可以说“每当请求类型 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=int
、T2=double
,而不管模板头中 T1 和 T2 的顺序如何。
此外,您还可以这样做
template <typename T>
struct A<T*, T*>;
并在A<int*, int*>
中使用它。现在很明显,类型变量列表与实际模板参数列表没有直接对应关系。
注意:术语 "pattern"、"type variable"、"type pattern matching" 不是标准的 C++ 术语。不过,它们几乎在其他任何地方都是标准的。
假设如下声明:
template <typename T> struct MyTemplate;
以下偏特化的定义似乎使用相同的字母T
来指代不同的类型。
template <typename T> struct MyTemplate<T*> {};
例如,我们来具体实例化一下:
MyTemplate<int *> c;
现在,再次考虑上面偏特化的定义:
template <typename T> struct MyTemplate<T*> {};
在这一行的第一部分(即template <typename T>
),T
是int *
。在该行的第二部分(即 MyTemplate<T*>
),T
是 int
!
那么,偏特化的定义是怎么读的呢?
你有这条线:
MyTemplate<int *> c;
您的困惑似乎来自假设 < >
中的 int *
以某种方式对应于 template <typename T>
中的 T
。它不是。在部分特化中(实际上在每个模板声明中),模板参数名称只是 "free variable"(或者可能是 "placeholder")名称。模板参数(int *
在你的例子中)不直接对应于这些,它们对应于模板名称后面的 < >
中的(或将是)内容。
这意味着实例化的 <int *>
部分映射到偏特化的 <T*>
部分。 T
只是由 template <typename T>
前缀引入的名称。整个过程中,T
就是int
。
这样读:
主模板说“
MyTemplate
是一个class具有一个类型参数的模板”:template <typename> struct MyTemplate;
部分专业化说,"whenever there exists a type
T
"...template <typename T>
... 这样就要求
MyTemplate
类型的特化T *
"...struct MyTemplate<T *>
...然后使用模板的替代定义。
您还可以定义明确的专业化。例如,可以说“每当请求类型
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=int
、T2=double
,而不管模板头中 T1 和 T2 的顺序如何。
此外,您还可以这样做
template <typename T>
struct A<T*, T*>;
并在A<int*, int*>
中使用它。现在很明显,类型变量列表与实际模板参数列表没有直接对应关系。
注意:术语 "pattern"、"type variable"、"type pattern matching" 不是标准的 C++ 术语。不过,它们几乎在其他任何地方都是标准的。