Infer the return type of a template function. Templates

10.1. Defining a Function Template

Sometimes it may seem that a strongly typed language makes it difficult to implement anything at all. simple functions. For example, although next algorithm The min() function is trivial, strong typing requires that variations of it be implemented for all the types we are going to compare:

int min(int a, int b) (

return a b ? a: b;

double min(double a, double b) (

return a b ? a: b;

A tempting alternative to explicitly defining each instance of the min() function is to use preprocessor-extensible macros:

#define min(a, b) ((a) (b) ? (a) : (b))

But this approach is fraught with potential dangers. The macro defined above works correctly when simple requests to min(), for example:

min(10.0, 20.0);

but it can bring surprises in more complex cases: such a mechanism does not behave like a function call, it only performs textual argument substitution. As a result, the values ​​of both arguments are evaluated twice: once when comparing a and b, and once when calculating the result returned by the macro:

#include iostream

#define min(a,b) ((a) (b) ? (a) : (b))

const int size = 10;

while (min(p++,ia) != ia)

cout "elem_cnt: "elem_cnt

" expecting: " size endl;

At first glance, this program counts the number of elements in an array ia of integers. But in this case, the min() macro expands incorrectly because the post-increment operation is applied to the pointer argument twice for each substitution. As a result, the program prints a line indicating incorrect calculations:

elem_cnt: 5 expecting: 10

Function templates provide a mechanism by which we can preserve the semantics of function definitions and calls (encapsulating a piece of code in one place in the program and ensuring that the arguments are evaluated once) without sacrificing the strong typing of the C++ language, as is the case with macros.

The template gives the algorithm used to automatic generation function instances with different types. The programmer parameterizes all or only some of the types in a function's interface (that is, the formal parameter and return value types), leaving its body unchanged. A function is well suited to be a template if its implementation remains invariant across a certain set of instances that differ in data types, as, say, in the case of min().

This is how the min() function template is defined:

template class Type

Type min2(Type a, Type b) (

return a b ? a: b;

// correct: min(int, int);

// correct: min(double, double);

min(10.0, 20.0);

If instead of the preprocessor macro min() we substitute this template into the text of the previous program, the result will be correct:

elem_cnt: 10 expecting: 10

(IN standard library C++ has function templates for many commonly used algorithms, such as min(). These algorithms are described in Chapter 12. And in this introductory chapter we present our own simplified versions of some of the algorithms in the standard library.)

Both the declaration and definition of a function template must always begin with the keyword template, followed by a comma-separated list of identifiers, enclosed in angle brackets " and ", a list of template parameters, which must be non-empty. A template can have type parameters, which represent a type, and constant parameters, which represent a fixed constant expression.

The type parameter consists of the class keyword or the typename keyword followed by an identifier. These words always indicate that the following name refers to a built-in or user-defined type. The name of the template parameter is chosen by the programmer. In the example above, we used the name Type, but we could have chosen anything else:

template class Glorp

Glorp min2(Glorp a, Glorp b) (

return a b ? a: b;

When instantiating (creating a specific instance) a template, the actual built-in or user-defined type is substituted for the type parameter. Any of the types int, double, char*, vectorint, or listdouble is a valid template argument.

The constant parameter looks like regular ad. It says that instead of the parameter name, the constant value from the template definition should be substituted. For example, size is a constant parameter that represents the size of the array arr:

template class Type, int size

Type min(Type (arr) );

Following the template parameter list is a function declaration or definition. If you do not pay attention to the presence of parameters in the form of type specifiers or constants, then the definition of a function template looks exactly the same as for ordinary functions:

template class Type, int size

/* parameterized function for searching

* minimum value in array */

Type min_val = r_array;

for (int i = 1; i size; ++i)

if (r_array[i] min_val)

min_val = r_array[i];

In that example Type determines the type of the value returned by the min() function, the type of the parameter r_array and the type of the local variable min_val; size specifies the size of the r_array array. During program operation, when using the min() function, any built-in and user defined types, and instead of size - certain constant expressions. (Recall that you can work with a function in two ways: call it or take its address).

The process of substituting types and values ​​for parameters is called template instantiation. (We'll go into more detail on this in the next section.)

The list of parameters for our min() function may seem very short. As discussed in Section 7.3, when the parameter is an array, a pointer to its first element is passed, but the first dimension of the actual array argument within the function definition is unknown. To get around this difficulty, we declared the first parameter to min() as a reference to the array, and the second as its size. The disadvantage of this approach is that when using a pattern with arrays of the same type int, but different sizes different instances of the min() function are generated (or instantiated).

The parameter name is allowed to be used within a template declaration or definition. The type parameter serves as a type specifier; it can be used just like any builtin or custom type, for example in variable declarations or type casting operations. A constant parameter is used as a constant value - where constant expressions are required, for example to specify the size in an array declaration or as initial value enumeration element.

// size determines the size of the array parameter and initializes

// type variable const int

template class Type, int size

Type min(const Type (r_array))

const int loc_size = size;

Type loc_array;

If an object, function, or type with the same name as a template parameter is declared in the global scope, the global name is hidden. In the following example, the type of the tmp variable is not double, but the same as the Type template parameter:

typedef double Type;

template class Type

Type min(Type a, Type b)

// tmp is the same type as the template parameter Type, not the given one

// global typedef

Type tm = a b ? a: b;

An object or type declared inside a function template definition cannot have the same name as any of the parameters:

template class Type

Type min(Type a, Type b)

// error: repeated declaration of the name Type that matches the name

// template parameter

typedef double Type;

Type tmp = a b ? a: b;

The name of the template type parameter can be used to specify the return type:

// correct: T1 represents the type of the value returned by min(),

// and T2 and T3 are the type parameters of this function

template class T1, class T2, class T3

In one list of parameters, a certain name is allowed to be used only once. For example, the following definition would be flagged as a compilation error:

// error: incorrect reuse parameter name Type

template class Type, class Type

Type min(Type, Type);

However, the same name can be used multiple times within a template declaration or definition:

// correct: reusing the Type name inside the template

template class Type

Type min(Type, Type);

template class Type

Type max(Type, Type);

The parameter names in the declaration and definition do not have to match. Thus, all three min() declarations refer to the same function template:

// all three min() declarations refer to the same function template

// forward template declarations

template class T T min(T, T);

template class U U min(U, U);

// actual template definition

template class Type

Type min(Type a, Type b) ( /* ... */ )

The number of times the same template parameter appears in the list of function parameters is unlimited. The following example uses Type to represent two different parameters:

// correct: Type is used repeatedly in the list of template parameters

template class Type

Type sum(const vectorType , Type);

If a function template has several type parameters, then each of them must be preceded by keyword class or typename:

// correct: typename and class keywords can be interleaved

template typename T, class U

// error: must be typename T, class U or

// typename T, typename U

template typename T, U

In a function template's parameter list, the keywords typename and class have the same meaning and are therefore interchangeable. Either of these can be used to declare different template type parameters in the same list (as demonstrated with the minus() function template). To denote a type parameter, it is more natural, at first glance, to use the keyword typename rather than class, because it clearly indicates that it is followed by a type name. However, this word was only recently added to the language as part of the C++ standard, so you'll likely see the word class in older programs. (Not to mention that class is shorter than typename, and humans are lazy by nature.)

The typename keyword makes it easier to parse template definitions. (We will only briefly dwell on why it was needed. For those wishing to learn more about this, we recommend that you refer to Stroustrup’s book “Design and Evolution of C++”.)

When parsing this way, the compiler must distinguish expressions that are types from those that are not; it is not always possible to identify this. For example, if the compiler encounters the expression Parm::name in a template definition, and if Parm is a type parameter that represents a class, should name be assumed to represent a type member of the class Parm?

template class Parm, class U

Parm::name * p; // is this a pointer declaration or a multiplication?

// Actually multiplication

The compiler does not know whether name is a type because the definition of the class represented by Parm is not available until the template is instantiated. For such a template definition to be parsed, the user must tell the compiler which expressions include the types. This is done using the typename keyword. For example, if we want the expression Parm::name in the minus() function template to be the name of a type and therefore the entire line to be treated as a pointer declaration, then we need to modify the text as follows:

template class Parm, class U

Parm minus(Parm* array, U value)

typename Parm::name * p; // now this is a pointer declaration

The typename keyword is also used in a template parameter list to indicate that the parameter is a type.

A function template can be declared as inline or extern, just like a regular function. The specifier is placed after the parameter list, not before the word template.

// correct: specifier after parameter list

template typename Type

Type min(Type, Type);

// error: inline specifier is not in place

template typename Type

Type min(ArrayType, int);

Exercise 10.1

Determine which of these function template definitions is incorrect. Correct the mistakes.

(a) template class T, U, class V

void foo(T, U, V);

(b) template class T

(c) template class T1, typename T2, class T3

(d) inline template typename T

T foo(T, unsigned int*);

(e) template class myT, class myT

void foo(myT, myT);

(f) template class T

(g) typedef char Ctype;

template class Type

Ctype foo(Ctype a, Ctype b);

Exercise 10.2

Which of the repeated template declarations are wrong? Why?

(a) template class Type

Type bar(Type, Type);

template class Type

Type bar(Type, Type);

(b) template class T1, class T2

void bar(T1, T2);

template typename C1, typename C2

void bar(C1, C2);

Exercise 10.3

Rewrite the putValues() function from Section 7.3.3 as a template. Parameterize it so that there are two template parameters (for the type of array elements and for the size of the array) and one function parameter that is a reference to the array. Write a definition of a function template.

From the Microsoft Office book author Leontyev Vitaly Petrovich

Choosing a template As we have already said, Publisher is designed to work in a “step-by-step” mode - we are, as it were, putting together a future publication piece by piece. And even more precisely, we create it based on one of countless templates. The Publisher CD contains over 1,500 templates

From book Help Guide in C++ author Stroustrap Bjarne

R.7.1.4 Type template specification A type template specification is used to specify a family of types or functions (see

From the book Effective Office Work author Ptashinsky Vladimir Sergeevich

The concept of a template To simplify the work of creating and formatting texts, standardize the arrangement and design of text, graphics, typify document processing operations, and other things, document templates are used. Microsoft package Office gives various definitions template

From the book Database Processing in Visual Basic®.NET author McManus Geoffrey P

From the book Creation Joomla templates author author unknown

Template Directory Structure Now we need to take care of some conditions. As already mentioned, the template must have a certain directory structure: [PathToJoomla!]/templates/[TemplateName]/[PathtoJoomla!]/templates/[TemplateName]/css/[PathtoJoomla!]/templates/[

From the XSLT book author Holzner Stephen

Template Structure In addition to a special title, a template needs structure. You can create a structure using tables or tags

. Next we describe creating a tabular version of the structure. If you still have Layout mode enabled in Dremweaver, close

From the book XSLT Technology author Valikov Alexey Nikolaevich

Creating a Template In Chapter 2, I created a basic template to select nodes in planets.xml and convert that document to HTML. Templates in style sheets are created using elements , defining the rules for the required transformations. We created a template that found the root

From the book The C Programming Language for personal computer author Bochkov S. O.

Template Body In fact, the xsl:template element that defines a template rule specifies nothing more than the conditions under which the rule should be executed. The specific actions and instructions that must be executed are determined by the contents of the xsl:template element and constitute

From the book The C Language - A Guide for Beginners by Prata Steven

Function Definition A function definition specifies the name, formal parameters, and body of the function. It may also specify the function's return type and storage class. The syntax for defining a function is:[<спецификация КП>][<спецификация

From the book Undocumented and Little-Known Features of Windows XP author Klimenko Roman Alexandrovich

Defining a Function with an Argument: Formal Arguments Our function definition begins with two lines: space(number)int number; The first line informs the compiler that the space() function has an argument and that its name is number. The second line is a description indicating

From the book How to make your own website and make money on it. A practical guide for beginners on making money online author Mukhutdinov Evgeniy

Creating a security template To create a security template based on any other template, select the Save As command from the template's context menu. The Microsoft Management Console will then prompt you to provide a name for the new template, after which it will appear in

From the C++ book for beginners by Lippman Stanley

From the author's book

10.2. Specifying a Function Template A function template describes how specific functions should be constructed when given many actual types or values. The design process is called template instantiation. It is executed implicitly, as a side effect of the call

From the author's book

From the author's book

10.11. Function Template Example This section provides an example that shows how function templates can be defined and used. This defines the sort() template, which is then used to sort the elements of the array. The array itself is represented by the Array class template (see

From the author's book

16.1. Defining a Class Template Let's say we need to define a class that supports a queuing mechanism. A queue is a data structure for storing a collection of objects; they are placed at the end of the queue and retrieved from the beginning. The behavior of the queue is described

You can prototype a function template by pre-declaring it. This declaration informs the compiler about the presence of the template and also informs the compiler about the expected parameters. For example, the Sort function template prototype would look like this:

template void Sort(T array, Tsize size);

The names of the formal parameters of a template may not be the same in the template pre-declaration and definition. So, for example, in the following snippet both the template prototype and the template definition refer to the same function:

template T max(T, T);

template

Type max(Type a, Type b)

if (a > b) return a; else return b;

Using a Function Template

A function template describes how a particular function can be constructed based on one or more actual types. The compiler automatically creates a function body representative for the types specified in the call. This process is called specification. It occurs when a template function is called.

For example, in the following example, the min() function is instantiated twice: once with type int and once with type double:

template

Type min(Type a, Type b)

if (a< b) return a; else return b;

int x = 4, y = 5, z;

double t = 6.56, r = 3.07, p;

Function Template Specialization

A specialized template function is a regular function whose name is the same as the function in the template, but which is defined for parameters of specific types. Specialized template functions are defined when a generic template is not suitable for a particular data type. For example, the template function min

template

Type min(Type a, Type b)

if (a< b) return a; else return b;

cannot be used for strings (for the char* type), since the compiler-generated code will simply compare their memory positions (addresses). To compare strings correctly, you can define a specialized function:

char* min(char* s1, char* s2)

if (strcmp(s1,s2)>0) return s2; else return s1;

Then you can access such a function in the same way as a template function:

int i1 = 3, i2 = 5;

cout<< “max int = ” << max(i1, i2) << endl;

char* s1 = “Golden Eagle”;

char* s2 = “Perigrine Falcon”;

cout<< “max str = “ << max(s1, s2) << endl;

Class Templates

Class template gives a general definition of a family of classes using arbitrary types or constants. Pattern defines template data members And template member functions. Once a class template has been defined, you can instruct the compiler to generate a new class based on it for a specific type or constant.

Class template syntax

template<<список аргументов шаблона>>

class<имя класса>

<тело класса>

The template keyword is followed by one or more arguments (parameters) enclosed in angle brackets and separated by commas. Each argument can be a class keyword followed by an identifier indicating the parameterized type. The template argument list cannot be empty.

Next comes the class definition. It is similar to a regular class definition, except that it uses a template argument list.

Template parameters consisting of the class keyword followed by an identifier are often called type parameters. In other words, they inform the compiler that the template expects a type as an argument.

We have already previously considered such a tool as templates in C++ when we created . Why you should use templates was written in the article with function templates. There we looked at the basic provisions of templates in C++. Let's remember them.

Any template begins with the word template, be it a function template or a class template. The template keyword is followed by angle brackets −< >, which list a list of template parameters. Each parameter must be preceded by the reserved word class or typename . The absence of these keywords will be interpreted by the compiler as . Some examples of template declarations:

Template

Template

Template

The typename keyword tells the compiler that the template will use a built-in data type such as: int , double , float , char , etc. And the class keyword tells the compiler that the function template will use custom data types as a parameter , that is, classes. But under no circumstances should you confuse a template parameter with a class template. If we need to create a class template with one parameter of type int and char , the class template will look like this:

Template

where T is a class template parameter that can accept any of the built-in data types, which is what we need.

And if the class template parameter must be of a custom type, such as Array , where Array is a class that describes an array, the class template will look like this:

Template class Name ( //class template body );

It’s better for you to figure this out from the beginning so that no errors arise later, even if the class template is written correctly.

Let's create a Stack class template, where , which stores similar data elements. You can push and pop data onto the stack. An element added to the stack is placed at the top of the stack. Elements of the stack are removed starting from the top. In the Stack class template, you need to create the main methods:

  • Push— add an element to the stack;
  • Pop- remove an element from the stack
  • printStack— displaying the stack on the screen;

So, let’s implement these three methods, and in the end we will get the simplest class that implements the operation of the stack structure. Don't forget about constructors and destructors. See the code below.

#include "stdafx.h" #include template << "Заталкиваем элементы в стек: "; int ct = 0; while (ct++ != 5) { int temp; cin >> << "\nУдаляем два элемента из стека:\n"; myStack.pop(); // удаляем элемент из стека myStack.pop(); // удаляем элемент из стека myStack.printStack(); // вывод стека на экран return 0; } // конструктор template Stack ::Stack(int s) ( size = s > Stack bool Stack bool Stack void Stack ::printStack() ( for (int ix = size -1; ix >= 0; ix--) cout<< "|" << setw(4) << stackPtr << endl; }

// code Code::Blocks

// Dev-C++ code

#include using namespace std; #include template class Stack ( private: T *stackPtr; // pointer to the stack int size; // stack size T top; // top of the stack public: Stack(int = 10); // by default the stack size is 10 elements ~Stack() ; // destructor bool push(const T); // push an element onto the stack bool pop(); // remove an element from the stack void printStack()); int main() ( Stack myStack(5); // fill the stack cout<< "Заталкиваем элементы в стек: "; int ct = 0; while (ct++ != 5) { int temp; cin >> temp; myStack.push(temp); ) myStack.printStack(); // print the stack to the screen cout<< "\nУдаляем два элемента из стека:\n"; myStack.pop(); // удаляем элемент из стека myStack.pop(); // удаляем элемент из стека myStack.printStack(); // вывод стека на экран return 0; } // конструктор template Stack ::Stack(int s) ( size = s > 0 ? s: 10; // initialize the stack size stackPtr = new T; // allocate memory for the stack top = -1; // value -1 indicates that the stack empty ) // template destructor Stack ::~Stack() ( delete stackPtr; // delete the stack ) // element is a function of the Stack class for placing an element on the stack // return value is true, the operation completed successfully // false, the element was not added to the stack template bool Stack ::push(const T value) ( ​​if (top == size - 1) return false; // the stack is full top++; stackPtr = value; // push the element onto the stack return true; // successful completion of the operation ) // element function Stack class to remove an element from the stack // return value is true, the operation completed successfully // false, the stack is empty template bool Stack ::pop() ( if (top == - 1) return false; // the stack is empty stackPtr = 0; // remove an element from the stack top--; return true; // successful completion of the operation ) // displaying the stack on the screen template void Stack ::printStack() ( for (int ix = size -1; ix >= 0; ix--) cout<< "|" << setw(4) << stackPtr << endl; }

As you can see, the Stack class template is declared and defined in the file with the main function. Of course, this method of recycling templates is no good, but it will do for an example. Lines 7 - 20 declare the class template interface. The class declaration is done in the usual way, and before the class there is a template declaration, on line 7. When declaring a class template, always use this syntax.

Lines 47 - 100 contain the template function element of the Stack class, and before each function it is necessary to declare a template, exactly the same as before the class - template . That is, it turns out that the function element of a class template is declared in exactly the same way as ordinary function templates. If we described the implementation of methods inside a class, then the template header would be template There is no need to register for each function.

To bind each function element to a class template, as usual we use the binary scope resolution operation - :: with the name of the class template - Stack . Which is what we did in lines 49, 58, 68, 83, 96.

Note the declaration of the myStack object of the Stack class template in the main function, line 24. The angle brackets must explicitly indicate the data type used; this was not necessary in the function templates. Next, main runs some functions that demonstrate how the Stack class template works. The result of the program is shown below.

We push elements onto the stack: 12 3456 768 5 4564 |4564 | 5 | 768 |3456 | 12 Remove two elements from the stack: | 0 | 0 | 768 |3456 | 12

Function templates, in other words, are instructions according to which local versions of a templated function are created for a specific set of parameters and data types.

In fact, function templates are a powerful tool in C++ that make a programmer's job much easier. For example, we need to program a function that would display the elements of an array. The task is not difficult! But to write such a function, we must know the data type of the array that we will display on the screen. And then they tell us - there is more than one data type, we want the function to output arrays of types int, double, float and char.

As it turned out, the task became more complicated. And now we understand that we need to program as many as 4 functions that perform the same actions, but for different types of data. Since we are not yet familiar with function templates, we will do this: we will use .

// overloading the printArray function to display the array on the screen void printArray(const int * array, int count) ( for (int ix = 0; ix< count; ix++) cout << array << " "; cout << endl; } void printArray(const double * array, int count) { for (int ix = 0; ix < count; ix++) cout << array << " "; cout << endl; } void printArray(const float * array, int count) { for (int ix = 0; ix < count; ix++) cout << array << " "; cout << endl; } void printArray(const char * array, int count) { for (int ix = 0; ix < count; ix++) cout << array << " "; cout << endl; }

Thus, we have 4 overloaded functions, for different data types. As you can see, they differ only in the function header; their body is absolutely the same. I wrote the function body once for the int type and copied it three times for other data types.

And, if you run the program with these functions, it will work properly. The compiler itself will determine which function to use when calling.

As you can see, there was quite a lot of code for such a simple operation. What if we need to program it as a function. It turns out that for each data type you will have to create your own function. That is, you yourself understand that the same code will be in several copies, this is of no use to us. That's why C++ came up with such a mechanism - function templates.

We create one template in which we describe all data types. This way the source will not be cluttered with unnecessary lines of code. Below we will look at an example program with a function template. So, let’s remember the condition: “program a function that would display the elements of the array.”

#include < count; ix++) cout << array << " "; cout << endl; } // конец шаблона функции printArray int main() { // размеры массивов const int iSize = 10, dSize = 7, fSize = 10, cSize = 5; // массивы разных типов данных int iArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; double dArray = {1.2345, 2.234, 3.57, 4.67876, 5.346, 6.1545, 7.7682}; float fArray = {1.34, 2.37, 3.23, 4.8, 5.879, 6.345, 73.434, 8.82, 9.33, 10.4}; char cArray = {"MARS"}; cout << "\t\t Шаблон функции вывода массива на экран\n\n"; // вызов локальной версии функции printArray для типа int через шаблон cout << "\nМассив типа int:\n"; printArray(iArray, iSize); // вызов локальной версии функции printArray для типа double через шаблон cout << "\nМассив типа double:\n"; printArray(dArray, dSize); // вызов локальной версии функции printArray для типа float через шаблон cout << "\nМассив типа float:\n"; printArray(fArray, fSize); // вызов локальной версии функции printArray для типа char через шаблон cout << "\nМассив типа char:\n";printArray(cArray, cSize); return 0; }

// code Code::Blocks

// Dev-C++ code

#include #include using namespace std; // function template printArray template void printArray(const T * array, int count) ( for (int ix = 0; ix< count; ix++) cout << array << " "; cout << endl; } // конец шаблона функции printArray int main() { // размеры массивов const int iSize = 10, dSize = 7, fSize = 10, cSize = 5; // массивы разных типов данных int iArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; double dArray = {1.2345, 2.234, 3.57, 4.67876, 5.346, 6.1545, 7.7682}; float fArray = {1.34, 2.37, 3.23, 4.8, 5.879, 6.345, 73.434, 8.82, 9.33, 10.4}; char cArray = {"MARS"}; cout << "\t\t Шаблон функции вывода массива на экран\n\n"; // вызов локальной версии функции printArray для типа int через шаблон cout << "\nМассив типа int:\n"; printArray(iArray, iSize); // вызов локальной версии функции printArray для типа double через шаблон cout << "\nМассив типа double:\n"; printArray(dArray, dSize); // вызов локальной версии функции printArray для типа float через шаблон cout << "\nМассив типа float:\n"; printArray(fArray, fSize); // вызов локальной версии функции printArray для типа char через шаблон cout << "\nМассив типа char:\n";printArray(cArray, cSize); return 0; }

Please note that the code has been reduced by 4 times, since only one instance of the function is declared in the program - the template. In main I declared several arrays - four, for data types: int, double, float, char. After which, in lines 26, 28, 30, 32, the printArray function is called for different arrays. The result of the program is shown below.

Template for displaying an array on the screen Array of type int: 1 2 3 4 5 6 7 8 9 10 Array of type double: 1.2345 2.234 3.57 4.67876 5.346 6.1545 7.7682 Array of type float: 1.34 2.37 3.23 4.8 5.879 6. 345 73.434 8.82 9.33 10.4 Array of type char: M A R S

As you can see, the program works correctly, and for this we only needed to define the printArray function once in the form that is familiar to us. Please note that before the declaration of the function itself, on line 5, there is the following template entry . This entry suggests that the printArray function is actually a function template, since the first parameter of printArray contains a const T* data type, exactly the same as in line 5.

All function templates begin with the word template followed by angle brackets that list the parameters. Each parameter must be preceded by the reserved word class or typename .

Template

Template

Template

The typename keyword tells the compiler that the template will use a built-in data type such as: int , double , float , char , etc. And the class keyword tells the compiler that the function template will use custom data types as a parameter , that is, classes.

Our function template used built-in data types, so on line 5 we wrote template . Instead of T, you can substitute any other name you can think of. Let's take a closer look at the code fragment from the top program, I'll post it separately.

// function template printArray template void printArray(const T * array, int count) ( for (int ix = 0; ix< count; ix++) cout << array << " "; cout << endl; } // конец шаблона функции printArray

Line 2 defines a template with one parameter, T, and this parameter will have one of the built-in data types because the typename keyword is specified.

Below, in lines 3 - 8, a function is declared that meets all the criteria for declaring a regular function, there is a header, there is a function body, the header contains the name and parameters of the function, everything is as usual. But what turns this function into a function template is a parameter with data type T , which is the only connection to the template declared earlier. If we wrote

Void printArray(const int * array, int count) ( for (int ix = 0; ix< count; ix++) cout << array << " "; cout << endl; }

then it would be a simple function for an array of type int .

So, in fact, T is not even a data type, it is a reserved place for any built-in data type. That is, when this function is called, the compiler parses the templated function's parameter and creates an instance for the appropriate data type: int, char, and so on.

Therefore, you should understand that even if the amount of code is smaller, this does not mean that the program will consume less memory. The compiler itself creates local copies of the template function and, accordingly, as much memory is consumed as if you had written all the function instances yourself, as is the case with overloading.
I hope I have conveyed the main idea about function templates to you. To reinforce the material, let's look at another example program using a function template.

#include "stdafx.h" #include #include < size; ix++) if (max < array) max = array; return max; } int main() { // тестируем шаблон функции searchMax для массива типа char char array = "aodsiafgerkeio"; int len = strlen(array); cout << "Максимальный элемент массива типа char: " << searchMax(array, len) << endl; // тестируем шаблон функции searchMax для массива типа int int iArray = {3,5,7,2,9}; cout << "Максимальный элемент массива типа int: " << searchMax(iArray, 5) << endl; return 0; }

// code Code::Blocks

// Dev-C++ code

#include #include using namespace std; // function template for finding the maximum value in the array template T searchMax(const T* array, int size) ( T max = array; // maximum value in the array for (int ix = 0; ix< size; ix++) if (max < array) max = array; return max; } int main() { // тестируем шаблон функции searchMax для массива типа char char array = "aodsiafgerkeio"; int len = strlen(array); cout << "Максимальный элемент массива типа char: " << searchMax(array, len) << endl; // тестируем шаблон функции searchMax для массива типа int int iArray = {3,5,7,2,9}; cout << "Максимальный элемент массива типа int: " << searchMax(iArray, 5) << endl; return 0; }

Here's another example of using function templates. The function template is declared on lines 5-13. The function must return the maximum value of the array, so the return value is of type T , because the data type of the array is not known in advance. By the way, a variable max of type T is declared inside the function; the maximum value of the array will be stored in it. As you can see, the T data type is used not only to specify function parameters, but also to indicate the return type, and can also be freely used to declare any variables within a function template.

Maximum element of an array of type char: s Maximum element of an array of type int: 9

Function templates can also be overloaded with other function templates by changing the number of parameters passed to the function. Another feature of overloading is that template functions can be overloaded with regular non-template functions. That is, the same function name is specified, with the same parameters, but for a specific data type, and everything will work correctly.

I was about to write a text about all sorts of cool data structures, and then it turned out that we had not yet examined several very important features of C++. Templates are one of them.

Templates are a very powerful tool. Template functions and classes can greatly simplify a programmer’s life and save a huge amount of time, effort and nerves. If you think that templates are not a very significant topic to study, know that you are mistaken.

Template functions

A simple example of a template function:

C++ code Type square (Type a) ( Type b; b = a*a; return b; ) int x = 5; int i; i = square(5); float y = 0.5; float f; f = square(y);

If we created functions the old fashioned way, then we would have to write two different functions: for the int type and for the float type. And if you needed the same function using other types, you would have to write it again. Using templates, you can limit yourself to just one instance of a function, leaving all the dirty work to the compiler.

Instead of using a specific type, the function uses a parametric type (or, in other words, a template argument). Here I called the parametric type the identifier Type. This identifier appears three times in a function: the return value, the function argument, and the definition of the variable s. That is, Type is used like any regular type.

But for the code to work, you need to add the following line before the function (I showed several syntax options, they all work):

C++ code template Type square (Type a) template < class Type >Type square (Type a) template< class Type >Type square (Type a)

So, the function must be preceded by the keyword template, and in angle brackets you must specify the name of the parametric type with the keyword class. Instead of the class keyword, you can use type - in general, there is no difference.

The parametric type identifier can also be anything. We will often use these: TypeA, TypeB, Datatype, T.

Important Note: Template functions must have an argument so that the compiler can determine which type to use.

You can use several parametric types in templates, and of course you can mix parametric types with standard ones (you just need to take care of the correct type casting). I will give an example that uses two parametric types TypeA, TypeB and the base type int:

C++ code template TypeB example_function (TypeA a, TypeB b) ( int x = 5; b = a + x; return b; )

But template functions are not the most interesting thing we'll look at today.

Template classes

In general, template classes are created in much the same way as template functions - the keyword template is written before the class name. Let's look at template classes using a stack as an example:

C++ code template class stack ( private: int top; Type s; public: stack (): top(0) () void push(Type var) ( top++; s = var; ) Type pop(); ); template Type stack::pop() ( Type var = s; top--; return var; ) Here we define

shared a stack of ten elements. These elements can be of any type, more on that below.

The only thing I want to draw your attention to is the definition of the push and pop functions. The push function is defined inside the class, and the pop function is defined outside it. For all functions declared outside the class, the template keyword must be specified. The expression before the function name is the same as the one before the class name.

Now let's see how to work with template classes:

C++ code stack s1; stack s2; s1.push(3); s1.push(2); s1.pop(); s2.push(0.5);

When creating an object, after the class name you need to put angle brackets in which to indicate the desired type. After this, the objects are used in the way we are used to.

Template classes have one amazing feature - in addition to standard types, they can also work with custom ones. Let's look at a small example. To do this, let's define a simple warrior class:

C++ code class warrior ( public: int health; warrior () : health(0) () ); stack s; warrior w1; warrior w2; warrior w3; s.push(w1); s.push(w3); s.pop(); s.push(w2);

Look, now you can put warrior type variables on stacks!!! You may not believe me, but this is very cool! You can see how cool this is when we create graphs and trees based on lists.

That's all according to the templates for now. Later we will look at more complex cases of using template classes.