12.4 Partial Class Template Specialization

Ru-Brd

Full template specialization is often useful, but sometimes it is natural to want to specialize a class template for a family of template arguments rather than just one specific set of template arguments. For example, let's assume we have a class template implementing a linked list:

 template<typename T>  class List {  // (1)  public:   void append(T const&);     inline size_t length() const;   }; 

A large project making use of this template may instantiate its members for many types. For member functions that are not expanded inline (say, List<T>::append() ), this may cause noticeable growth in the object code. However, we may know that from a low-level point of view, the code for List<int*>::append() and List<void*>::append() is the same. In other words, we'd like to specify that all List s of pointers share an implementation. Although this cannot be expressed in C++, we can achieve something quite close by specifying that all List s of pointers should be instantiated from a different template definition:

 template<typename T>  class List<T*> {  // (2)  private:      List<void*> impl;   public:   void append(T* p) {          impl.append(p);      }      size_t length() const {          return impl.length();      }   }; 

In this context, the original template at point (1) is called the primary template , and the latter definition is called a partial specialization (because the template arguments for which this template definition must be used have been only partially specified). The syntax that characterizes a partial specialization is the combination of a template parameter list declaration ( template<...> ) and a set of explicitly specified template arguments on the name of the class template ( <T*> in our example).

Our code contains a problem because List<void*> recursively contains a member of that same List<void*> type. To break the cycle, we can precede the previous partial specialization with a full specialization:

 template<>  class List<void*> {  // (3)    void append (void* p);      inline size_t length() const;   }; 

This works because matching full specializations are preferred over partial specializations. As a result, all member functions of List s of pointers are forwarded (through easily inlineable functions) to the implementation of List<void*> . This is an effective way to combat so-called code bloat (of which C++ templates are often accused).

There exists a number of limitations on the parameter and argument lists of partial specialization declarations. Some of them are as follows :

  1. The arguments of the partial specialization must match in kind (type, nontype, or template) the corresponding parameters of the primary template.

  2. The parameter list of the partial specialization cannot have default arguments; the default arguments of the primary class template are used instead.

  3. The nontype arguments of the partial specialization should either be nondependent values or plain nontype template parameters. They cannot be more complex dependent expressions like 2*N (where N is a template parameter).

  4. The list of template arguments of the partial specialization should not be identical (ignoring renaming) to the list of parameters of the primary template.

An example illustrates these limitations:

 template<typename T, int I = 3>  class S;  // primary template  template<typename T>  class S<int, T>;  // ERROR: parameter kind mismatch  template<typename T = int>  class S<T, 10>;  // ERROR: no default arguments  template<int I>  class S<int, I*2>;  // ERROR: no nontype expressions  template<typename U, int K>  class S<U, K>;  // ERROR: no significant difference   //        from primary template  

Every partial specialization ”like every full specialization ”is associated with the primary template. When a template is used, the primary template is always the one that is looked up, but then the arguments are also matched against those of the associated specializations to determine which template implementation is picked. If multiple matching specializations are found, the "most specialized" one (in the sense defined for overloaded function templates) is selected; if none can be called "most specialized," the program contains an ambiguity error.

Finally, we should point out that it is entirely possible for a class template partial specialization to have more parameters than the primary template. Consider our generic template List (declared at point (1)) again. We have already discussed how to optimize the list-of-pointers case, but we may want to do the same with certain pointer-to-member types. The following code achieves this for pointer-to-member-pointers:

 template<typename C>  class List<void* C::*> {  // (4)  public:  // partial specialization for any pointer-to-  void*  member   // every other pointer-to-member-pointer type will use this  typedef void* C::*ElementType;   void append(ElementType pm);      inline size_t length() const;   };  template<typename T, typename C>  class List<T* C::*> {  // (5)  private:      List<void* C::*> impl;   public:  // partial specialization for any pointer-to-member-pointer type   // except pointer-to-  void*  member which is handled earlier;   // note that this partial specialization has two template parameters,   // whereas the primary template only has one parameter  typedef T* C::*ElementType;   void append(ElementType pm) {          impl.append((void* C::*)pm);      }      inline size_t length() const {          return impl.length();      }   }; 

In addition to our observation regarding the number of template parameters, note that the common implementation defined at (4) to which all others are forwarded (by the declaration at point (5)) is itself a partial specialization (for the simple pointer case it is a full specialization). However, it is clear that the specialization at point (4) is more specialized than that at point (5); thus no ambiguity should occur.

Ru-Brd


C++ Templates
C++ Templates: The Complete Guide
ISBN: 0201734842
EAN: 2147483647
Year: 2002
Pages: 185

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net