How to read the template partial specialization?

前端 未结 4 1374
不思量自难忘°
不思量自难忘° 2021-01-20 06:16

Suppose the following declaration:

template  struct MyTemplate;

The following definition of the partial specialization se

相关标签:
4条回答
  • 2021-01-20 06:24

    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.

    0 讨论(0)
  • 2021-01-20 06:27

    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.)

    0 讨论(0)
  • 2021-01-20 06:35

    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.

    0 讨论(0)
  • 2021-01-20 06:38

    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.

    0 讨论(0)
提交回复
热议问题