Table of Contents
-
- class template specialization
-
- class template specialization
-
- full specialization
- partial specialization
- specialized template
- Traits Technology
- Type classification
- Reduce code bloat
Class template specialization
Class template specialization
The following is a standard class template that does not use any template specialization techniques
So no matter what type the template parameter T is, Stack has the same behavior
template <typename T> class Stack {<!-- --> private: std::vector<T> elems; ... }
There are two forms of class template specialization:
- full class template specialization
- partial class template specialization
Full specialization
Definition: Refers to providing a single implementation for a specific type when all template parameters are determined
The code below indicates that when the template parameter is a specific std::string
, use all the codes after the sequence number 2 to instantiate the class
full specialization requirements
- template content should be empty
- class defines the data types that require specialization
- Number three fills in all the operations that need to be performed on the specialized data type
template<> ① class Stack<std::string> {<!-- --> ② private: std::deque<std::string> elems; ③ public: void push(std::string const & amp; elem) {<!-- --> elems.push_back(elem); } void pop(){<!-- --> if (elems.empty()) return; elems. pop_back(); } std::string top() const{<!-- --> if (elems.empty()) return NULL; return elems.back(); } }
Partial specialization
Definition: Provide a single implementation for a specific type when a part of the template parameters are determined
The following code means that when the template parameters we pass in T
all have T*
characteristics, use the following code to perform class instantiation
template <typename T> ① class Stack<T*> {<!-- --> ② private: std::list<T*> list; ③ public: void push(T* & amp; elem) {<!-- --> list.push_front(elem); } void pop(){<!-- --> if (list.empty()) return; list. pop_front(); } T* top() const{<!-- --> if (list.empty()) return NULL; return list. front(); } }
Specialized template
Suppose there is currently a main class template
template <typename T1, typename T2> class MyClass {<!-- --> … };
Then the corresponding specialized class template can be written like this
Indicates that the received second template parameter T2 must be of type int
template <typename T> class MyClass<T,int> {<!-- --> … };
For example, there are some specializations, you can refer to the following code
template <typename T1, typename T2> class MyClass<T1*,T2*> {<!-- --> … };
Traits Technology
Definition: The Traits technique is a programming technique used in object-oriented programming to achieve code reuse and composability. Traits technology allows programmers to define reusable components that can be used by multiple classes or objects and can be combined at runtime
Here’s a simple case of using the traits
technique
// Declare a template class fp_traits to implement the characteristics of the floating point type template <typename numT> struct fp_traits {<!-- --> }; // Template specialization, specifying fp_traits of type float template<> struct fp_traits<float> {<!-- --> typedef float fp_type; // define typedef as float type enum {<!-- --> max_exponent = FLT_MAX_EXP }; // Define the enumeration constant, representing the maximum exponent of float type static inline fp_type epsilon() // Define the inline function and return the minimum value of type float {<!-- --> return FLT_EPSILON; } }; // Template specialization, specifying fp_traits of type double template<> struct fp_traits<double> {<!-- --> typedef double fp_type; // define typedef as double type enum {<!-- --> max_exponent = DBL_MAX_EXP }; // Define the enumeration constant, representing the maximum exponent of double type static inline fp_type epsilon() // Define the inline function and return the minimum value of type double {<!-- --> return DBL_EPSILON; } }; // Declare the template class matrix, and use the numT template parameter to represent the numeric type in the matrix template <typename numT> class matrix {<!-- --> public: typedef numT num_type; // define typedef as numT type typedef fp_traits<num_type> num_type_info; // define typedef as fp_traits<num_type> type // Define the inline function and return the result of the epsilon() function in num_type_info inline num_type epsilon() {<!-- -->return num_type_info::epsilon();} ?… }; int main() {<!-- --> matrix <float> fm; // define a matrix object of type float matrix <double> dm; // define a matrix object of double type cout << "float matrix: " << fm.epsilon() << endl; // Output the result of the epsilon() function of the float type matrix object cout << "double matrix: " << dm.epsilon() << endl; // Output the result of the epsilon() function of the double type matrix object }
Type classification
Definition: Since cpp comes with few type processing methods, the method of using class template specialization technology to design a special class template to provide the required information is called type classification technology
// type template, used to provide type information for the specified type T template<typename T> class TypeInfo {<!-- --> public: enum {<!-- --> IsPtrT = 0, IsRefT = 0, IsArrayT = 0 }; // Define three enumeration constants, indicating that T is not a pointer, not a reference, not an array typedef T baseT; // define typedef as T type typedef T bottomT; // define typedef as T type }; // Type template specialization to provide type information for pointer type T* template<typename T> class TypeInfo<T*> {<!-- --> public: enum {<!-- --> IsPtrT = 1, IsRefT = 0, IsArrayT = 0 }; // Define three enumeration constants, indicating that T* is a pointer, not a reference, not an array typedef T baseT; // define typedef as T type typedef typename TypeInfo<T>::bottomT bottomT; // define typedef as TypeInfo<T>::bottomT type }; // Type template specialization to provide type information for reference type T & amp; template<typename T> class TypeInfo<T &> {<!-- --> public: enum {<!-- --> IsPtrT = 0, IsRefT = 1, IsArrayT = 0 }; // Define three enumeration constants, indicating that T & amp; is not a pointer, a reference, or an array typedef T baseT; // define typedef as T type typedef typename TypeInfo<T>::bottomT bottomT; // define typedef as TypeInfo<T>::bottomT type }; // Type template specialization to provide type information for an array type T[N] of size N template<typename T, size_t N> class TypeInfo <T[N]> {<!-- --> public: enum {<!-- --> IsPtrT = 0, IsRefT = 0, IsArrayT = 1 }; // Define three enumeration constants, indicating that T[N] is not a pointer, not a reference, but an array typedef T baseT; // define typedef as T type typedef typename TypeInfo<T>::bottomT bottomT; // define typedef as TypeInfo<T>::bottomT type };
Reduce code bloat
Definition: Whenever we use a type as a template parameter to instantiate a class template or function template, the C++ compiler will generate a class or function corresponding to the type, which will cause repeated generation for each instantiation , resulting in code bloat
example
// Define a Vector type object VPVector, the element type is void*, that is, a pointer to any type Vector<void*> VPVector; // Define a template class Vector<T*>, where T is a pointer type and inherits from VPVector template<class T> class Vector <T*>: public VPVector{<!-- --> public: // Overload the [] operator and return a pointer of type T* T* & amp; operator[](int i) {<!-- --> return (T* & amp;)(VPVector::operator[](i)); }; }; int main() {<!-- --> // Define an object v1 of type Vector<int*> to store pointers of type int Vector<int*> v1; // Define an object v2 of type Vector<double*> to store pointers of type double Vector<double*> v2; // Define a variable i of type int and initialize it to 3, assign the address of i to the first element in v1 int i = 3; v1[0] = &i; // Define a variable d of double type and initialize it to 3.14, assign the address of d to the first element in v2 double d = 3.14; v2[0] = &d; }