问题
Suppose the following declaration:
template <typename T> struct MyTemplate;
The following definition of the partial specialization seems to use the same letter T
to refer to different types.
template <typename T> struct MyTemplate<T*> {};
For example, let's take a concrete instantiation:
MyTemplate<int *> c;
Now, consider again the above definition of the partial specialization:
template <typename T> struct MyTemplate<T*> {};
In the first part of this line (i.e. template <typename T>
), T
is int *
. In the second part of the line (i.e. MyTemplate<T*>
), T
is int
!
So, how is the definition of the partial specialization read?
回答1:
Read it like this:
The primary template says "
MyTemplate
is a class template with one type parameter":template <typename> struct MyTemplate;
The partial specialization says, "whenever there exists a type
T
"...template <typename T>
... such that a specialization of
MyTemplate
is requested for the typeT *
"...struct MyTemplate<T *>
... then use this alternative definition of the template.
You could also define explicit specializations. For example, could say "whenever the specialization is requested for type
X
, use this alternative definition:template <> struct MyTemplate<X> { /* ... */ };
Note that explicit specializations of class templates define types, wheras partial specializations define templates.
To see it another way: A partial class template specialization deduces, or pattern-matches, the structure of the class template arguments:
template <typename T> struct MyTemplate<T *>
// ^^^^^^^^^^^^ ^^^^^
// This is a new template Argument passed to the original class
// template parameter
The parameter names of this new template are matched structurally against the argument of the original class template's parameters.
Examples:
MyTemplate<void>
: The type parameter of the class template isvoid
, and the primary template is used for this specialization.MyTemplate<int *>
: The type parameter isint *
. There exists a typeT
, namelyT = int
, such that the requested type parameter isT *
, and so the definition of the partial specialization of the template is used for this specialization.MyTemplate<X>
: The parameter type isX
, and an explicit specialization has been defined for that parameter type, which is therefore used.
回答2:
The correct reading of the specialisation is as follows:
template <typename T> // a *type pattern* with a *free variable* `T` follows
struct MyTemplate<T*> // `T*` is the pattern
When the template is instantiated by MyTemplate<int*>
, the argument is matched against the pattern, not the type variable list. Values of the type variables are then deduced from the match.
To see this more directly, consider a template with two arguments.
template <typename T1, typename T2>
struct A;
and its specialisation
template <typename T1, typename T2>
struct A<T1*, T2*>;
Now you can write the latter as
template <typename T2, typename T1>
struct A<T1*, T2*>;
(the variable list order is reversed) and this is equivalent to the previous one. Indeed, order in the list is irrelevant. When you invoke A<int*, double*>
it is deduced that T1=int
, T2=double
, regardless of the order of T1 and T2 in the template head.
Further, you can do this
template <typename T>
struct A<T*, T*>;
and use it in A<int*, int*>
. It is now plainly clear that the type variable list has no direct correspondence with the actual template parameter list.
Note: the terms "pattern", "type variable", "type pattern matching" are not standard C++ terms. They are pretty much standard almost everywhere else though.
回答3:
You have this line:
MyTemplate<int *> c;
Your confusion seems to come from assuming that the int *
in < >
somehow corresponds to the T
in template <typename T>
. It does not. In a partial specialisation (actually in every template declaration), the template parameter names are simply "free variable" (or perhaps "placeholder") names. The template arguments (int *
in your case) don't directly correspond to these, they correspond to what is (or would be) in the < >
following the template name.
This means that the <int *>
part of the instantiation maps to the <T*>
part of the partial specialisation. T
is just a name introduced by the template <typename T>
prefix. In the entire process, the T
is int
.
回答4:
There is no contradiction. T should be read as T, T* is T*.
template <typename T> struct MyTemplate<T*> {};
"In the first part of this line (i.e. template <typename T>
), T is int *."
No - in template <typename T>
T is int, in struct MyTemplate<T*> {};
T is also int.
"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++, 4th ed, 25.3, p. 732.)
来源:https://stackoverflow.com/questions/31770746/how-to-read-the-template-partial-specialization