1. Global specialization
1. All kinds of specialization
- Which type is difficult to use, we should specialize in which type
- Making a full class specialization of the class template is equivalent to rewriting a class, and this class is specifically for the previously difficult type
2. Membership specialization
Which member function is difficult to use, we can specialize which member function
#include <iostream> #include <cstring> using namespace std; // Therefore, the add function in this class is not suitable for const char * type, because the pointer cannot add template<class T> class CMath{ public: CMath(T const& t1, T const t2):m_t1(t1), m_t2(t2){} T add(void){ return m_t1 + m_t2; } private: T m_t1; T m_t2; }; // Full class specialization is equivalent to rewriting a class for a specific type (char* const) /* template<> class CMath<char* const>{ public: CMath(char* const& t1, char* const& t2):m_t1(t1), m_t2(t2){} char* const add(void){ return strcat(m_t1, m_t2); } private: char* const m_t1; char* const m_t2; }; */ // It's troublesome because only the add function is not suitable for char* const type. Just rewrite the add function // All have member specialization template<> char* const CMath<char* const>::add(void){ return strcat(m_t1, m_t2); } int main(void){ CMath<int> m1(1, 1); std::cout << m1.add() << std::endl; // 2 // The character array name is char* const char c_x[256] = "hello ", c_y[256] = "world!"; // When cmath < char * const >, you won't use the class template to instantiate the class, but directly use the specialized class CMath<char* const>m2(c_x, c_y); cout << m2.add() << endl; // hello world! return 0; }
2. Local specialization
- The difference from global specialization is that several type parameters are specialized. If all type parameters are specialized into specific types, it is global specialization. If only some type parameters are specialized, it is local specialization.
#include <iostream> using namespace std; // Class template template <class T, class D> class A{ public: // static is written here so that it can be called directly through a class without instantiating an object static void foo(){ cout << "1. A<T, D>::foo()" << endl; } }; // Local specialization, specialization D into short template <class T> class A<T, short>{ public: static void foo(){ cout << "2. A<T, short>::foo()" << endl; } }; // Local specialization, specialization D into T template <class T> class A<T, T>{ public: static void foo(){ cout << "3. A<T, T>::foo()" << endl; } }; int main(void){ A<int, double>::foo(); // 1. A<T, D>::foo() A<int , short>::foo(); // 2. A<T, short>::foo() // A<short, short>::foo(); // Compilation reports an error, resulting in ambiguity between 2 and 3 return 0; }
3. Type parameter default
#include <iostream> #include <typeinfo> using namespace std; // Class template template <class T = short, class D = double> class A{ public: void print(void){ cout << "m_t: " << typeid(m_t).name() << "," << "m_d: " << typeid(m_d).name() << endl; } private: T m_t; D m_d; }; int main(void){ A<int, float> m1; m1.print(); // m_t: i,m_d: f A<>m2; m2.print(); // m_t: s,m_d: d }
4. Template parameters of numerical shape
- Type parameters can appear in the type parameter table. Numerical parameters can also have default values
- Can't appear string, double this kind of type, can only appear numeric parameter, can only appear int type?
- size_t is long unsigned int
#include <iostream> using namespace std; // Type parameters can appear in the type parameter table. Numerical parameters can also have default values template<class T, size_t S =10> class Array{ public: // operators overloading T& operator[](size_t i){ return m_arr[i]; } size_t size(){ return S; } private: T m_arr[S]; }; int main(void){ // Array<int> a; A can be regarded as a one-dimensional array class, and each element in the array is of type int // m can be regarded as a one-dimensional array. Each element in the array is of type array < int > and is a one-dimensional array // So m is a two-dimensional array Array<Array<int, 3> ,3> m; // The last two < are written separately to avoid ambiguity for (int i=0; i<m.size(); i++){ for (int j=0; j<m.size(); j++){ m[i][j] = 1; } } for (int i=0; i<m.size(); i++){ for (int j=0; j<m.size(); j++){ cout << m[i][j] << " "; } cout << endl; } return 0; }
$ ./a.out 1 1 1 1 1 1 1 1 1
5. Template skills
Personally, I don't think the latter two are common, but now that I see them, I'll write about them and leave a seed. In case I encounter them in future development, it's also easy to expand.
5.1 template member variables
- m_s is first a member variable, and then an unknown class instantiated by the class template array, because D is unknown
#include <iostream> using namespace std; template<class T> class Array{ public: // operators overloading T& operator[](size_t i){ return m_arr[i]; } private: T m_arr[10]; }; template <class D> class Sum{ public: Sum(Array<D>& s):m_s(s){} D add(){ //Sum D d = 0; for(int i = 0; i < 10; i++){ d += m_s[i]; } return d; } private: Array<D> m_s; // Template member variable }; int main(void){ Array<int> a; for (int i = 0; i < 10; i++){ a[i] = i + 1; } // Sum class template instantiates a class sum < int > to instantiate an object s, and uses a to assign the initial value Sum<int> s(a); cout << s.add() << endl; //55 return 0; }
5.2 template member function
Member function template of class template
- foo is a function template and a member function, which can be directly called member function template
- To put it bluntly, a member function template is nested in the class template. When using, you need to instantiate the class first and then the function
#include <iostream> using namespace std; template <class T> class A{ public: // The declaration definition is written together template<class D> void foo(){ //Member function template cout << "A<T>::foo()" << endl; } // Declaration definitions are written separately template<class X> void foo2(); }; // Since it is template nesting, there are two hats. There should also be scope restrictions template<class T> template<class X> void A<T>::foo2(){ cout << "A<T>::foo2()" << endl; } int main(void){ // 1. Instantiation class A<int> m; // 2. Instantiation class m.foo<double>(); // A<T>::foo() m.foo2<double>(); // A<T>::foo2() return 0; }
5.3 template member type
#include <iostream> using namespace std; // Class template nested class template template <class X>class A{ public: template <class Y>class B{ public: template <class Z>class C; }; }; // Class template C is implemented externally template <class X> template <class Y> template <class Z> class A<X>::B<Y>::C{ // Turn over the scope twice public: // Here is another member function template, which needs to be instantiated template<class T>void foo(){ cout << "zhen e xin" << endl; } }; int main(void){ A<int>::B<int>::C<int> a; a.foo<int>(); // "zhen e xin" return 0; }
5.4 template parameters
- The template parameters in < > can be type, value or class template
- In the figure above, array is a class template whose template parameter is T
- Sum is also a class template. Its template parameter is C and its type is a class template: template < class D > class C. the default value is class template array. This is the template type template parameter
#include <iostream> using namespace std; template<class T> class Array{ public: // operators overloading T& operator[](size_t i){ return m_arr[i]; } private: T m_arr[10]; }; template <class D, template<class M> class C> class Sum{ public: // Sum(Array<D>& s):m_s(s){} Sum(C<D>& s):m_s(s){} D add(){ //Sum D d = 0; for(int i = 0; i < 10; i++){ d += m_s[i]; } return d; } private: // Array<D> m_s; C<D> m_s; // Template member variable }; int main(void){ Array<int> a; for (int i = 0; i < 10; i++){ a[i] = i + 1; } // Sum class template instantiates a class sum < int > to instantiate an object s, and uses a to assign the initial value // Sum<int> s(a); Sum<int, Array> s(a); cout << s.add() << endl; //55 return 0; }