After the first two lectures, I want to introduce the basic knowledge of c + + templates more comprehensively. This lecture will assume that you have the basic knowledge of the last two lectures.
1. Key sub typename
In the process of c + + standardization, the key sub typename is introduced to illustrate that the identifier inside the template can be a type
For example:
template<typename T> class MyClass { typename T::SubType* ptr; ...... };
The second typename indicates that SubType is a type defined inside class T
If there is no declaration of the second typename, write it directly in the following form
T::SubType* ptr;
The compiler will think: SubType It is a static member variable in class T, so the above code will be interpreted as:
T: : product of subtype and PTR (T::SubType) * ptr)
two . Template construction (note the small points before the template)
Let's look at examples first
template<int N> void printBitset(std::bitset<N> const& bs){ std::cout<<bs.template to_string<char,char_traits<char>,allocator<char> >(); }
You will find a strange thing bs.template. In fact, we want to call it like this
bs.to_string<char,char_traits<char>,allocator<char> >();
bs is an STD:: BitSet < n > const & type object. We want to call to.string under this object
But there is a problem, how does the compiler distinguish between the following <, > which is the template < >, or the larger <, >
Therefore, the. template structure is used to tell the compiler that the < >, which you see later, is not a relatively large < >
3. Use - > this
example
template <typename T> class Base { public: void exit(); }; template <typename T> class Derived : Base<T> { public: void foo() { exit(); //Call external exit() or report an error directly } };
If called directly, the compiler will either report an error or call other exit() functions with the same name. Anyway, it will not call the exit() function inherited from the parent class
If you want to call a function inherited from the parent class, you should write it like this
this->exit(); //perhaps Base<T>::exit();
4. Member template
A member in a template class can also be a template
example
template <typename T> class Stack { private: std::deque<T> elems;//Container for storing elements public: void push(T const&);//Push void pop();//Out of stack T top() const;//Return stack top element inline bool empty() const { return elems.empty(); } //The stack with element type T2 is used for assignment template <typename T2> Stack<T>& operator= (Stack<T2> const&); } template<typename T> inline template<typename T2> Stack<T>& Stack<T>::operator= (Stack<T2> const& op2) { if((void*)this == (void*)&op2) {//We don't want to assign values to ourselves return *this; } Stack<T2> tmp(op2); //Copy a copy elems.clear(); //Empty existing elements while(!tmp.empty()){ elems.push_back(tmp.back()); tmp.pop_back(); } return *this; }
5. Template parameters of template
It's quite long. I wrote a separate article
6. Zero initialization
We hope that when we use a template, even if we do nothing, its internal initialization has been done to avoid some unexpected things.
//For function templates template<typename T> void f() { T x = T(); //Adding T is int, that is, int x = int();, In this way, x will be initialized to 0 } //For class templates template<typename T> class MyClass { private: T x; public: MyClass() : x(...) {//Confirm that x is initialized, as are other built-in object types ..... } }
7. Use the string as the argument of the function template
Sometimes there are unexpected things when passing a string to the reference of a function template, which is related to the type derivation of the template and the degradation of the array. If you don't know what I'm talking about, you can see my related articles
give an example
#include <string> template<typename T> inline T const& max (T const& a, T const& b) { return a < b ? a : b; } int main() { std::string s(); ::max("apple", "peach"); //Correct, same type parameter ::max("apple", "tomato");//Error, different type parameters ::max("apple", s);//Error, arguments of different types } Because it is T const&,So arrays don't degenerate. that apple and peach yes const char[6]type tomato yes const char[7]type s It's a string type
A good solution is to overload max() for the string.