C++ Basic Technology Deepening (Template) (10) - "C++ Templates"

Posted by zed420 on Fri, 31 May 2019 23:00:45 +0200

PS:
template template parameters (double template parameters) are class templates placeholders, which are declared in a manner similar to class templates.

Parametric declaration

The difference between template and class or function is that the template declaration statement has a parameterized clause:
template <...parameters here...>
Or:
export template <...parameters here>
The following two templates are shown: one is within the class, i.e. member templates, and the other is outside the class and within the namespace scope (global scope is also known as a namespace scope):

template <typename T>
class List{//namespace scope class template
public:
    template <typename T2>
    List(List<T2> const&);//member function template
    ...
};

template <typename T>
template <typename T2>
List<T>::List(List<T2> const& b){
    ...
}
template <typename T>
int Length(List<T> const&);//namespace scope function template

class Collection{
    template<typename T>
    class Node{//member class template
        ...
    };

    template <typename T>
    class Handle;//member class template, undefined

    template <typename T>
    T* alloc(){//member function template,Imply as inline function
        ...
    }
    ...
};

template <typename T>
class Collection::Handle{//member class template
    ...
};

member templates outside the definition domain class can have multiple templates < <... >... > Parametric clauses, one of which represents the template itself, and the other clauses represent each layer of class template on the periphery. These clauses must start with the outermost class templates.

Functiontemplate can have a default call argument, just like general function:

template <typename T>
void report_top(Stack<T> const&,int number=10);

template <typename T>
void fill(Array<T>*,T const&=T());//If T is built-in, T() is 0 or false

When fill() is called, if the caller provides a second argument value, the default argument will not be instantiated, which ensures that compilation errors will not occur if the default argument cannot be instantiated for a particular type of T. Examples are as follows:

class value{
public:
    Value(int);
};
void init(Array<Value>* array){
    Value zero(0);
    fill(array,zero);//OK
    fill(array);//ERROR: Value has no default constructor, so the call failed
}

In addition to the two basic types of templates, three other declarations can also be parameterized, all of which correspond to the member definitions of the class template:
1) the definition of member functions of class templates;
2) the definition of nested class members (nested class members) of class templates;
3) static member variable definition of class templates.
Although they can also be parameterized, they are not first-level templates. Their parameters are determined entirely by the template to which they belong. Examples are as follows:

template <int I>
class CupBoard{
    void open();
    class Shelf;
    static double total_weight;
    ...
}

template <int I>
void CupBoard<T>::open(){
    ...
}
template <int I>
class CupBoard<I>::Shelf{
    ...
};
template <int I>
double CupBoard<I>::total_weight=0.0;
  • Virtual member function

The reason that member function templates cannot be declared virtual is that the virtual function calling mechanism uses a fixed-size table in which each entry records a virtual function entry. However, it is not known how many member function templates need to be instantiated until the entire program is compiled, so it conflicts with the virtual function calling mechanism.
But class template members can be virtual functions, because when class is instantiated, the number of member function s is already determined, so it can be virtual functions.

template <typename T>
class Dynamic{
public:
    //class template Of member function,Can be declared asvirtual
    virtual ~Dynamic();
    //member function template, cannot be declared virtual
    template <typename T2>
    virtual void copy(T2 const&);
};
  • Naming mechanism of template

Each template must have a unique name in its scope unless it is overloaded function templates. It's important to note that class template can't share the same name with other different kinds of objects, which is different from the general non-template class.

int C;
class C;//class names and nonclass names are in different spaces

int X;
template <typename T>
class X;//ERROR: Name conflicts with variable X above

struct S;
template <typename T>
class S;//ERROR: Name conflicts with the above struct S

template usually uses external links, but can't use C links. The only exception is static namespace scope function templates. template can't be declared inside the function by default:

extern "C++" tempalte <typename T>
void normal();

There is also a non-standard form of links

extern "Xroma" template <typename T>
void Xroma_link();
tempalte <typename T>
void external();//Shoot directly at objects of the same name and scope in another file

tempalte <typename T>
static void internal();//It has nothing to do with the template of the same name in another file
  • Primary Template

The declaration statement of the main template does not add a template argument list enclosed in angle brackets after the template name:

template <typename T> class Box;//OK:primary template
template <typename T> class Box<T>;//error:non-primary template
template <typename T> void translate(T*);//ok:primary template
template <tyepname T> void translate<T>(T*);//error:non-primary template

Once we declare a partial template, a non-primary template is generated.

Template Parameter

There are three types of template parameters:
1) Type parameters (type parameters):
2) Nontype parameters (untyped parameters):
3) template template parameters (double template parameters).
template parameters are variables of life in the parameterized clause of the template declaration statement. template parameters are not necessarily named:

template <typename,int>
class X;

But when template parameters need to be used in template code, the latter must be named. Note that template parameters declared later can use the name of template parameters declared earlier:

template <typename T,T* Root,template <T*> class Buf>
class Structure;

Now let's break each one.

  • Type Parameters

Category parameters are imported by keyword typename or class, which are completely equivalent. The keyword typename or class is followed by a simple identifier, which can be followed by a comma to partition the next parameter, or a closing clause with a right-hand bracket, or an equal sign to represent the preset template independent variable.
The function of type parameter in template declaration statement is very similar to the name of typedef. For example, you can't use a name like class T. Timely T does represent a class.

template <typename Allocator>
class List{
    class Allocator* allocator;//ERROR
    friend class Allocator;//ERROR
    ...
};
  • Nontype Parameters

The essence of untyped parameters is that the constants of their values can be determined at compile time or link time. The type of this parameter must be one of the following three:
Integer (int) or enum type;
pointers: point to regular objects, perform functions, and point to members;
reference: Points to objects and functions.
You may be surprised to find that there is typename in front of non-type parameter, as shown below:

template <typename T,typename T::Allocator* Allocator>
class List;

Nontype parameters can also be function or array types, but they all degenerate into corresponding pointer types:

template<int buf[5]>
class Lexer;
tempalte <int* buf>
class Lexer;

Nontype template param

Te eters'declaration protection four is very similar to variable declarations, but you can't add modifiers like static, mutable, but you can add const or volatile, but if these modifiers appear at the outermost level of parameter types, the compiler will ignore them:

template <int const length> //const is ignored
class Buffer;
template <int length>
class Buffer;//Equivalent to the previous line declaration statement

Finally, it is emphasized that non-type parameters are always right values: they cannot be addressed or assigned.

Template Template Parameters
Template Template Parameter is a class template placeholder, which is declared in a manner similar to class templates, but cannot use the keywords struct and union.

template <template<typename X> class C>//OK
void f(C<int>* p);

template <template<typename X> struct C>//ERROR: The keyword struct cannot be used
void f(C<int>* p);

template <template<typename X> union C>//ERROR: Can't use the keyword union
void f(C<int>* p);

Within their scope, you can use template parameters as you would use class template.
Template template parameters can also have default template arguments (default template arguments). If the client does not specify variables for the corresponding parameters, the compiler will use these preset variables:

template <template <typename T,typename A=MyAllocator> class Container>
class Adaptation{
    Container<int> storage;//Equivalent to Container < int, MyAllocator >
    ...
};

In template template parameter s, the name of template parameter can only be used in other parameter declarations of template parameter, as shown below:

template <template<typename T,T*> class Buf>
class Lexer{
    static char storage[5];
    Buf<char,&lexer<Buf>::storage[0]> buf;
    ...
};
template <template<typename T> class List>
class Node{
    static T* storage;//ERROR: template template parameters cannot be used hereT
    ...
};

In order to prevent the problems mentioned above, the template parameters name in template template parameter is not usually used elsewhere. Therefore, template parameters that are not used can be anonymous. Examples are as follows:

template <template <typename,typename=MyAllocator> class Container>
class Adaption{
    Container<int> storage;//Equivalent to Container < int, MyAllocator >
    ...
};
  • Default Template Arguments

You can refer to this blog for setting default template parameters: default template arguments for both function and class templates
No matter what template parameters can have default variables, of course, it must match the corresponding parameters. Obviously, the default template variables can not depend on their own parameters, but can depend on the parameters declared before:

template <typename T,typename Allocator=allocator<T> >
class list;

Like the presupposed independent variables of a function, the condition that a parameter has a presupposed independent variable is that all subsequent parameters have presupposed independent variables.
Usher arguments for subsequent parameters are usually unloaded in the same template declaration statement, but can also be written in an earlier declaration statement of the template. For example:

template <typename T1,typename T2,typename T3,typename T4=char,typename T5=char>
class Quintuple;//OK

template <typename T1,typename T2,typename T3=char,typename T4,typename T5>
class Quintuple;//OK

template <typename T1=char,typename T2,typename T3,typename T4,typename T5>
class Quintuple;//ERROR:T1 cannot have default values because T2 does not have default values

At the same time, we cannot repeat the default template argument.

template <typename T=void>
class Value;

template <typename T=void>
class Value;//ERROR: Presupposed variables are redefined

Unfinished...