c + + template -- basic knowledge

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

Type derivation of template

Type derivation of auto

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.

Tags: C++

Posted on Tue, 19 Oct 2021 16:18:28 -0400 by houssam_ballout