class template in c++

C++'s class templates provide a better way to generate generic class declarations. Templates provide parameterized types, that is, the ability to pass the type name as a parameter to the receiver to create a class or function.

First, define the class template

#include <iostream>
#include <string>
using namespace std;
template <class T1,class T2>
class Pair
{
public:
    T1 key;  //keywords
    T2 value;  //value
    Pair(T1 k,T2 v):key(k),value(v) { };
    bool operator < (const Pair<T1,T2> & p) const;
};
template<class T1,class T2>
bool Pair<T1,T2>::operator < (const Pair<T1,T2> & p) const
//Pair's member function operator <
{ //"Small" means the keyword is small
    return key < p.key;
}
int main()
{
    Pair<string,int> student("Tom",19); //Instantiate a class Pair<string,int>
    cout << student.key << " " << student.value;
    return 0;
}

You cannot put template member functions in a separate implementation file (previously, C++ provided the keyword export to allow you to put template member functions in a separate implementation file, but there are not many supported compilers, C++11 does not then use such keywords), since templates are not functions and cannot be compiled separately, templates must be used with a specific template instantiation request, for this, the easiest way is to put all template information in a header file and add it in Include this header file in the files that will use these templates.

Merely including a template in a program does not generate a template class, but must request instantiation. To do this, declare an object of type template class by replacing the generic name with the desired concrete type.

2. In-depth discussion of template classes

pointer stack

Can a built-in type or a class object be used as a type for a class template, is a pointer okay? The answer is yes, you can create a stack of pointers, but if you don't make major changes to the program, it won't work very well. The compiler can create classes, but the effect varies from person to person.

Array template example and non-type parameters

Templates are often used as container classes because the concept of type parameters is ideal for using the same storage scheme for different types. Indeed, providing reusable code for container classes was the main motivation for introducing templates, so let's look at another example that dives into several other aspects of template design and use. Specifically, some non-type (or expression) parameters and how to use arrays to handle inheritance families will be explored.

First introduce a simple array template that allows specifying the size of the array. One way is to use dynamic arrays and constructor parameters in the class to provide the number of elements, as was done in the last version of the Stack template. Another way is to use a template parameter to provide the size of a regular array, which is what C++11's new template array does.

#ifndef ARRAYTP_H_
#define ARRAYTP_H_
#include <iostream>
#include <cstdlib>

template<class T, int n>
class ArrayTP {
private:
    T at[n];
public:
    ArrayTP() {};

    explicit ArrayTP(const T &v);

    virtual T &operator[](int i);

    virtual T operator[](int i) const;
};

template<class T, int n>
ArrayTP<T, n>::ArrayTP(const T &v) {
    for (int i = 0; i < n; i++) {
        at[i] = v;
    }
}

template<class T, int n>
T &ArrayTP<T, n>::operator[](int i) {
    if (i < 0 || i >= n) {
        std::cerr << i << "is out of range\n" << std::endl;
        std::exit(EXIT_FAILURE);
    }
    return at[i];
}

template<class T, int n>
T ArrayTP<T, n>::operator[](int i) const {
    if (i < 0 || i >= n) {
        std::cerr << i << "is out of range\n" << std::endl;
        std::exit(EXIT_FAILURE);
    }
    return at[i];
}

#endif

The keyword class (or the equivalent keyword typename in this context) indicates that T is a type parameter, and int indicates that n is of type int. Such parameters (specifying a special type rather than being used as a generic name) are called non-type or expression parameters. Suppose there is the following declaration:

ArrayTP<double, 10> arrayTp(3.14);

This creates an object of type storage double, the compiler replaces T with double and n with 10.

Expression parameters have some display, expression parameters can be integers, enumerations, references or pointers. Therefore, double n is illegal, but double *pm is legal. In addition, template code cannot modify the value of the parameter, nor can it use the address of the parameter, so expressions such as n++ or &n cannot be used in this template. , when the template is instantiated, the value used as the expression parameter must be a constant expression.

Column requirements for expression parameters but each array size will generate its own template, that is, the following declaration will generate two separate class declarations:

ArrayTP<double, 10> arrayTp1(3.14);
ArrayTP<double, 12> arrayTp2(3.14);

Template Versatility

The same techniques used for regular classes can be used for template classes. Template classes can be used as base classes, as component classes, and as type parameters for other templates. For example, a stack template can be implemented using an array template, or an array can be constructed using an array template - an array element is a stack based on the stack template.

Templates can also be used recursively

ArrayTP<Array<int,5>,10> twodee;

The equivalent regular array declaration is as follows

int twodee[10][5];

default parameters

Another new feature of plank is the ability to provide default values ​​for type parameters.

template <class T1, class T2 = int> 
class Topo {
	...
}

Third, the specificity of the template

Class templates are similar to function templates in that there can be implicit instantiation, explicit instantiation, and explicit specialization, which are collectively called specialization. A template describes a class in a generic way, while a reification is to generate a class declaration with a concrete type.

3.1. Implicit instantiation

So far, all the template examples in this chapter have used implicit instantiation, that is, they declare one or more objects, indicating the desired type, and the compiler generates concrete classes using the recipe provided by the generic template definition:

ArrayTP <int,100> stuff;

The compiler does not generate an implicit instantiation of the class until the object is required:

ArrayTP <double,100> *tp;
tp = new ArrayTP <double,100>;

The second statement causes the compiler to generate a class definition and create an object from that definition.

3.2. Explicit instantiation

When a class is declared using the keyword template and indicating the desired type, the compiler will generate an explicit instantiation of the class declaration. The declaration must be in the same namespace as the template definition. For example, the following declaration declares ArrayTP<string,100> as a class;

template class ArrayTP <int,100>;

In this case, although no class object is created or mentioned, the compiler will also generate class declarations (including method definitions). As with implicit instantiation, reification will be generated from the generic template.

3.3. Explicit reification

explicit specialization is the definition of a specific type (used to replace generics in templates). Sometimes, it may be necessary to modify the template to behave differently when instantiated for a particular type. In this case, explicit materializations can be created.

Assuming the template uses the > operator to compare values, this works for numbers, and if T represents a class, it works as long as the T::operator>() method is defined; but if T is represented by a const char * String, this will not work, in this case a reification scheme can be used, providing an explicit template reification, which will use the template defined for the concrete type instead of the template defined for the generic type, when both the reified template and the generic template are specified with When an instantiated request matches, the compiler will use the materialized version.

Reified class template definition format

template <> class Classname<specialized-type-name> {...};

Earlier compilers may only recognize earlier formats, which do not support prefixes

class Classname<specialized-type-name> {...};

To provide a template for const char* using the new notation, you can use code similar to the following

template <> class ArrayTp<chonst char*> {
	...
};

3.4. Partialization

C++ also allows partial specialization, which partially limits the generality of templates. For example, partial reification can specify a concrete type for one of the type parameters

// Generic template
template <class T1,class T2> class Pair {...}
// Partial Reification
template <class T1> class Pair<T1,int> {...}

The <> declaration after the keyword template is an unspecified type parameter. So the second declaration above reifies T2 as an int, but leaves T1 unchanged, note that if you specify all types, the inside <> will be empty, which will result in an explicit reification.

tempplate <> class Pair<int,int> {...}

If there are multiple templates to choose from, the compiler will use the most specific template.

3.5, member template

Templates can be used as members of structs, classes, or template classes, and this feature is required to achieve a fully STL design.

#ifndef ARRAYTP_H_
#define ARRAYTP_H_

#include <iostream>

using std::cout;
using std::endl;

template<typename T>
class beta {
private:
    template<typename V>
    class hold {
    private:
        V val;
    public:
        hold(V v = 0) : val(v) {}

        void show() const { cout << val << endl; }

        V value() const { return val; }
    };

    hold<T> q;
    hold<int> n;
public:
    beta(T t, int i) : q(t), n(i) {}

    template<typename U>
    U blab(U u, T t) { return (n.value() + q.value()) * u / t; }

    void show() const {
        q.show();
        n.show();
    }
};

#endif


int main() {
    beta<double> guy(3.5,3);
    guy.show();
    cout << "U was set to int" << endl;
    cout << guy.blab(10,2.3) << endl;
    cout << "U was set to double" << endl;
    cout << guy.blab(10.0,2.3) << endl;
    
    // We can also explicitly convert
    cout << guy.blab<int>(10.0,2.3) << endl;
}

4. Using Templates as Parameters

As you know, a template can contain type parameters such as typename T and non-type parameters int n, and a template can also be a parameter of the template itself. This parameter is a new feature of the template and is used to implement STL.

template <template <typename T> class Thing>

The template parameter is template < typename T > class Thing, where template < typename T > class is the type Thing is the parameter, what does this mean, assuming the following declaration

Crab<King> legs;

In order for the above declaration to be accepted, the template parameter King must be a template class whose declaration matches the declaration of the template parameter Thing

template <typename T>
class King {...}

5. Template aliases

It is convenient to be able to specify aliases for types, especially in template design. Template reifications can be aliased using typedef s:

typedef std::array<double,12> arrd;
typedef std::array<int,12> arri;
typedef std::array<std::string,12> arrs;

arrd gallons;
arri days;
arrs months;

C++11 added the Intent feature, which uses templates to provide a series of aliases.

template <typename T>
using arrtype = std::array<T,12>;

This defines arrtype as a template alias that can be used to specify the type as follows:

arrtype<double> gallons;
arrtype<int> days;
arrtype<std::string> months;

C++11 allows the syntax using= to be used for non-templates, which is equivalent to regular typedef s for non-templates

Tags: Algorithm C++ programming language

Posted by mY.sweeT.shadoW on Sun, 02 Oct 2022 13:26:17 +0530