How to read the template partial specialization?

自古美人都是妖i 提交于 2019-12-20 02:43:06

问题


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:

  1. The primary template says "MyTemplate is a class template with one type parameter":

    template <typename> struct MyTemplate;
    
  2. The partial specialization says, "whenever there exists a type T"...

    template <typename T>
    

    ... such that a specialization of MyTemplate is requested for the type T *"...

    struct MyTemplate<T *>
    

    ... then use this alternative definition of the template.

  3. 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 is void, and the primary template is used for this specialization.

  • MyTemplate<int *>: The type parameter is int *. There exists a type T, namely T = int, such that the requested type parameter is T *, and so the definition of the partial specialization of the template is used for this specialization.

  • MyTemplate<X>: The parameter type is X, 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!