官术网_书友最值得收藏!

Specialization

Similar to function specialization, the explicit specialization of a class template defines a different implementation for a primary template when a specific type is passed as a template parameter. However, it is still a class template and you need to get the real code by instantiation.

For example, let's suppose that we have a struct X template that can store one element of any data type, and it has just one member function named increase(). But for the char type data, we want a different implementation of increase() and need to add a new member function called toUpperCase() to it. Therefore, we decide to declare a class template specialization for that type. We do this as follows:

  1. Declare a primary class template:
template <typename T>
struct X {
X(T init) : m(init) {}
T increase() { return ++m; }
T m;
};

This step declares a primary class template in which its constructor initializes the m member variable and increase() adds one to m and returns its value.

  1. Next, we need to perform specialization for the char type data:
template <>  //Note: no parameters inside <>, it tells compiler 
//"hi i am a fully specialized template"
struct X<char> { //Note: <char> after X, tells compiler
// "Hi, this is specialized only for type char"
X(char init) : m(init) {}
char increase() { return (m<127) ? ++m : (m=-128); }
char toUpperCase() {
if ((m >= 'a') && (m <= 'z')) m += 'A' - 'a';
return m;
}
char m;
};

This step creates a specialized (with respect to the primary class template) class template with an additional member function, toUpperCase(), for the char type data only.

  1. Now, we run a test:
int main() {
X<int> x1(5); //line A
std::cout << x1.increase() << std::endl;

X<char> x2('b'); //line B
std::cout << x2.toUpperCase() << std::endl;
return 0;
}

Finally, we have a main() function to test it. In line A, x1 is an object that has been implicitly instantiated from the primary template, X<T>. Since the initial value of x1.m is 5, 6 will be returned from x1.increase(). In line Bx2 is an object instantiated from the specialization template, X<char>, and the value of x2.m is b when it is executed. After calling x2.toUpperCase(), B will be the return value.

The complete code for this example can be found at  ch4_6_class_template_specialization.cpp.

In summary, the syntax that's used in the class template's explicit specialization is as follows:

template <> class[struct] class_name<template argument list> { ... }; 

Here, the empty template parameter list, template <>, is used to explicitly declare it as a template specialization and <template argument list> is the type parameter(s) to be specialized. For example, in ex4_6_class_template_specialization.cpp, we use the following:

template <> struct X<char> { ... };

Here, <char> after X identifies the type we are going to declare a template class specialization for.

Additionally, when we do specializations for a template class, all its members even those that are identical in the primary template must be defined because there is no inheritance concept for the primary template during template specializations.

Next, we'll take a look at partial specialization. This is a general statement of explicit specialization. Compared to the format of explicit specialization, which only has a template argument list, both the template parameter list and argument list are required for a partial specialization. For a template instantiation, the partial specialization template will be selected by the compiler if a user's template argument list matches a subset of the template arguments. Then, a new class definition from the partial specialization template will be generated by the compiler.

In the following example, for the primary class template A, we can partially specialize it for const T in the argument list. Note that both of them have the same parameter list, which is <typename T>:

//primary class template A
template <typename T> class A{ /* ... */ };

//partial specialization for const T
template <typename T> class A<const T>{ /* ... */ };

In the following example, the primary class template B has two parameters: <typename T1 and typename T2 >. We partially specialize it by T1=int, keeping T2 unchanged:

//primary class template B
template
<typename T1, typename T2> class B{ /* ... */ };

//partial specialization for T1 = int
template <typename T2> class B<int, T2>{ /* ... */};

Finally, in the following example, we can see that the number of template parameters in a partial specialization does not have to match the parameter numbers that appeared in the original primary template. However, the number of template arguments (appearing after the class name in angle brackets) must match the number and type of the parameters in the primary template:

//primary class template C: template one parameter
template <typename T> struct C { T type; };

//specialization: two parameters in parameter list
//but still one argument (<T[N]>) in argument list
template <typename T, int N> struct C<T[N]>
{T type; };

Again, a class template partial specialization is still a class template. You must provide definitions for its member functions and number variables separately.

To end this section, let's summarize what we've learned so far. In the following table, you can see a comparison between function and class templates, their instantiation, and specialization:

 
        
           Function Templates           Class Templates           Comments
Declaration            
template <class T1, class T2>
void f(T1 a, T2 b) { ... }            
template <class T1, class T2>
class X { ... };            
The declaration defines a function/class template, <class T1, class T2> called template parameters.
Explicit
Instantiation
 
            template void f <int, int >( int, int);
or
extern template
void f <int, int >( int, int);
(since C++11)           template class X<int, float>;
or
extern template class X<int,float>;
(since C++11)           After instantiation there are now functions/classes, but they are called template functions/classes.
Implicit
Instantiation           {
...
f(3, 4.5);
f<char, float>(120, 3.14);
}             {
...
X<int,float> obj;
X<char, char> *p;
}           When a function call or a class object/pointer is declared, if it has not been explicitly instantiated, the implicit instantiation approach used.
Specialization
 
            template <>
void f<int,float>(int a, float b)
{ ... }           template <>
class X <int, float>{ ... };           A fully customized version (no parameter list) of the primary template still needs to be instantiated.
Partial Specialization            
template <class T>
void f<T,T>(T a, T b)
{ ... }             template <class T>
class X <T, T>{ ... };           A partial customized version (has a parameter list) of the primary template still needs to be instantiated.

 

Five concepts need to be emphasized here:

  • Declaration: We need to follow the syntax that's used to define a function or class template. At this point, a function or class template by itself is not a type, a function, or any other entity. In other words, there are only template definitions in the source file and no code, which can be complied to an object file, is generated.
  • Implicit Instantiation: For any code to appear, a template must be instantiated. During this process, it becomes imperative to determine the template arguments so that the compiler can generate an actual function or class. In other words, they are compiled on-demand, which means that compiling the code of a template function or class does not happen until an instantiation with specific template arguments is given.
  • Explicit Instantiation: Tells the compiler to instantiate the template with the given types, regardless of whether they are used. Typically, it is used for providing libraries.
  • Full Specialization: This has no parameter list (fully customized); it only has an argument list. The most useful thing about template specialization is that you can create special templates for particular type arguments.
  • Partial Specialization: This is similar to fully specialization, but is part parameter list (partially customized) and part argument list.
主站蜘蛛池模板: 阿巴嘎旗| 浏阳市| 沈丘县| 肃宁县| 五原县| 绥江县| 云南省| 湖口县| 尉氏县| 华坪县| 鄂伦春自治旗| 工布江达县| 阳江市| 白城市| 固镇县| 石首市| 白银市| 新郑市| 望城县| 石阡县| 万宁市| 柞水县| 福贡县| 西乡县| 宁阳县| 江门市| 如东县| 肥城市| 禄劝| 东海县| 纳雍县| 香河县| 临海市| 涪陵区| 兰州市| 海淀区| 达拉特旗| 延津县| 武汉市| 兴城市| 高唐县|