C++ Templates

Chapter IV Non-type template parameters

Estimated reading time of 4 minutes 18 Views

For function templates and class templates, template parameters are not limited to types, and normal values can also serve as template parameters.

When using a value-based (value) template, these values must be clearly specified in order for the template to be exemplified and finally coded.

4.1 非类型的类模板参数

Now a fixed number of elements is used to achieve itstack The advantage of this method of realization is that additional memory costs can be avoided, either in the personal management of the memory or in the management of the memory using standard containers.
However, it's difficult to determine the size of a cage:

  • If the specified container is too small, the stack may spill over.
  • If the specified containers are too large, they may lead to unnecessary memory waste.

One solution is to specify the size of the stack based on the use of data, at which point the array size can be defined as a template parameter:

#include <stdexcept>

template<typename T, int MAXSIZE>
class Stack{
public:
    Stack();
    void push(const T&);
    void pop();
    T top() const;
    bool empty() const { return numElems == 0; }
private:
    int numElems;
    T elems[MAXSIZE];
};

template<typename T, int MAXSIZE>
void Stack::Stack():numElems(0){ /* ... */ }

template<typename T, int MAXSIZE>
void Stack<T, MAXSIZE>::push(const T& elem){
    if(numElems == MAXSIZE) throw std::out_of_range("Stack<>::push(): stack is full");
    elems[numElems++] = elem;
}

template<typename T, int MAXSIZE>
void Stack<T, MAXSIZE>::pop() const{
    if(numElems <= 0) throw std::out_of_range("Stack::pop(): empty stack");
    --numElems;
}

template<typename T, int MAXSIZE>
T Stack<T, MAXSIZE>::top() const{
    if(numElems <= 0) throw std::out_of_range("Stack::top(): empty stack");
    return elems[numElems - 1];
}
C++

MAXSIZEis the new second template parameter, typeint I don't know. It specifies the maximum number of stacks that can be contained in an array:

template<typename T, int MAXSIZE>
class Stack{
    ...
private: T elems[MAXSIZE];
    ...
};
C++

push()Check if the inn is full:

template<typename T, int MAXSIZE>
void Stack<T, MAXSIZE>::push(){
    if(numElems == MAXSIZE) throw std::out_of_range("Stack<>::push(): stack is full");
    elems[numElems++] = elem;
}
C++

Before using this type of template, it is necessary to specify the type and number of elements simultaneously:

#include <stdexcept>
#include <iostream>

template<typename T, int MAXSIZE>
class Stack{
public:
    Stack();
    void pop();
    void push(const T&);
    T top() const;
    bool empty() const { return numElems == 0; }
private:
    int numElems;
    T elems[MAXSIZE];
};

template<typename T, int MAXSIZE>
Stack<T, MAXSIZE>::Stack():numElems(0){ }

template<typename T, int MAXSIZE>
void Stack<T, MAXSIZE>::push(const T& elem){
    if(numElems == MAXSIZE) throw std::out_of_range("Stack<>::push(): stack is full");
    elems[numElems++] = elem;
}

template<typename T, int MAXSIZE>
void Stack<T, MAXSIZE>::pop(){
    if(numElems == 0) throw std::out_of_range("Stack<>::pop(): empty stack");
    --numElems;
}

template<typename T, int MAXSIZE>
T Stack<T, MAXSIZE>::top() const{
    if(numElems == 0) throw std::out_of_range("Stack<>::top(): empty stack");
    return elems[numElems - 1];
}

int main(){
    try{
        Stack<int, 20> int20Stack;
        Stack<int, 40> int40Stack;
        Stack<std::string, 40> stringStack;

        int20Stack.push(7);
        std::cout << int20Stack.top() << '\n';
        int20Stack.pop();

        stringStack.push("hello");
        std::cout << stringStack.top() << '\n';
        stringStack.pop();
        stringStack.pop();
    }catch(const std::exception& ex){
        std::cerr << "Exception: " << ex.what() << '\n';
        return EXIT_FAILURE;
    }
}
C++

As can be seen from the code above, each example template has its own type, so int20Stack and int40Stack are different types, and there is no significant or hidden type conversion between the two types, so they cannot be replaced or given value.

Similarly, default values can be specified for template parameters:

template<
        typename T = int,
        int MAXSIZE = 100
        >
class Stack{
    ...
};
C++

For the example above, it is not appropriate to use default values from the point of view of optimal design, since the specified default values may not be appropriate for the type and size of a stack, and it is therefore preferable to specify them in a visible manner.

4.2 非类型的函数模板参数

Similar to a class template parameter, you can also define non-type parameters for a function template.
The following function template defines a set of functions to add specific values:

template<
         typename T,
         int VAL
        >
T addValue(const T& x){ return x + VAL; }
C++

It is very useful to use functions or operations as parameters, which are often used in an iterative, as it is possible to customize the behaviour of an iterative.

For example, by means of the Standard Template Library (STL), examples of this function template can be passed to each element of the pool, with each element adding an integer value:

std::transform(source.begin(),      // appoint the beginning of target
               source.end(),        // appoint the end of target
               dest.begin(),        // appoint the beginning of receiver
               addValue<int, 5>);   // operation to each element
C++

std::transform() function template addValue() , the effect is to make the type int Add 5 to the element, source group source Each of these elements is called after the example. addValue() function and place the call result in the target group dest

However, the reality is that: addValue(5) is an example of a function template, which is usually seen as a collection used to name a set of multiple functions (even if there is only one function in the set), which is currently available C++ standard, the collection of the heavy-mount function is not used for the evolution of the template parameters, and therefore the specific type of reference for this function template has to be converted to:

std::transform(source.begin(),
               source.end(),
               dest.begin(),
               (int(*)(const int&)) addValue<int, 5>);
C++

4.3 非类型模板参数的限制

Non-type template parameters are limited, as they are usually integers (including number count values) or pointers to external links.

Float-type objects (class-type) are not allowed as non-type template parameters:

  • Floating points cannot be used as non-type template parameters
template<double VAT>
double process(double v) { return v * VAT; }
C++
  • Class object cannot be a non-type template parameter
template<std::string name>
class MyClass{

};
C++

Because string text is an internal link object (because two strings with the same name but in different modules are two completely different objects), they cannot be used as templates:

template<const char* name>
class MyClass{

};
...
MyClass<"hello"> x;
/* error: valid argument or string here */
C++

Furthermore, a global pointer cannot be used as a template parameter:

template<const char* name>
class MyClass{

};
...
const char* s = "hello";
MyClass<s> x;
/* s is a pointer to the eternal object */
C++

However, this can be used to link an external object:

template<const char* name>
class MyClass{

};
...
extern const char s[] = "hello"; // extern s
MyClass<s> x;
C++

4.4 小结

  • Templates can have value template parameters, not just type template parameters.
  • For non-type template parameters, floating point numbers, class-type objects and internal link objects (e.g. string) cannot be used as a reference.

Leave a Comment

Share this Doc

Chapter IV Non-type template parameters

Or copy link

CONTENTS
Remember to rest.