Generalization in functions. Template functions. Keywords template, class, typename. Explicit specialization of template function. Overloading of template function

Generalization in functions. Template functions. Keywords template, class, typename. Explicit specialization of template function. Overloading of template function


Contents


1. Generalization in functions. The concept of template functions. The general form of the declaration of template function. Keywords template, class, typename

The concept of a template in a function means using a generic data type as input and output parameters of a function. Instead of a specific data type, the function uses some generic type that bears a common name, for example T.

The general form of a generalized function that takes input parameters of a generalized type T, has the form:

template <class T> return_type FunName(list_of_parameters)
{
    // ...
}

where

  • return_type – the type that the function returns;
  • Fun_Name – the name of the template function;
  • list_of_parameters – the parameters of template function that have a generic type T.

When declaring a templated function, the keyword typename can be used instead of the class keyword. In this case, the general form of the generalized function will be:

template <typename T> return_type FunName(list_of_parameters)
{
   // ...
}

For example. The declaration of a function that receives as an input parameter a variable of the generalized type T and returns the value of the generalized type T has the form:

template <class T>
T FunName(T parameterName)
{
    // the body of function
    // ...
}

where

  • FunName – the name of generalized function;
  • T – the name of generalized type. When declaring a template function, this name can be any, for example TYPE;
  • parameterName – parameter name of the generic type T, which is used in the FunName function.

 

2. Examples of generalized (templated) functions

Example 1. The example implements the Add() template function, which adds two parameters of the generic type TT. The main() function demonstrates the use of the Add() function.

#include "stdafx.h"
#include <iostream>
using namespace std;

// Template function that returns the sum of two values of type TT
template <class TT>
TT Add(TT t1, TT t2)
{
    return t1 + t2;
}

int main()
{
    // Using the template function Add()
    // 1. For double type
    double d1 = 3.85, d2 = 2.50;
    double d3;
    d3 = Add(d1, d2); // d3 = 6.35

    // 2. For int type
    int i1 = 25;
    int i2 = 13;
    int i3;
    i3 = Add(i1, i2); // i3 = 38

    // 3. For string type
    string s1 = "abc";
    string s2 = "def";
    string s3 = Add(s1, s2); // s3 = "abcdef"

    return 0;
}

As you can see from the example, the template function

template <class TT>
TT Add(TT t1, TT t2)
{
    return t1 + t2;
}

used to sum parameters of types double, int, string. In this function, the generic type is named TT.

Example 2. The Equal() template function is implemented, which compares two input parameters of a generic type X. The function returns true if the parameter values are the same. Otherwise, the function returns false.

#include "stdafx.h"
#include <iostream>
using namespace std;

// a function that compares two input parameters of type X
template <typename X>
bool Equal(X a, X b)
{
    return a==b;
}

int main()
{
    // using of the template function Equal()
    bool res;
    res = Equal(5, 6); // res = 0
    res = Equal("abcd", "abcd"); // res = 1
    res = Equal(5.5, 5.5); // res = 1
    res = Equal('A', 'B'); // res = 0
    return 0;
}

As you can see from the example, the call to the Equal() function is performed for different types: int, string, double, char.

 

3. How the compiler works when using the template function

If the compiler encounters a template function, it generates versions of the function for any application with a particular type. That is, if the template function is called for types double, int, string, then the compiler generates 3 versions of the function for each type.

For example. Let a function be set that adds two parameters of a generalized type T:

T Add(T t1, T t2)
{
    return t1 + t2;
}

The next time you call this function

int a = Add(3, 8);
double d = Add(3.8, 2.9);
string s = Add("Hello ", "world!");

the compiler will generate the following implementations of the Add() function:

int Add(int t1, int t2)
{
    return t1 + t2;
}

double Add(double t1, double t2)
{
    return t1 + t2;
}

string Add(string t1, string t2)
{
    return t1 + t2;
}

Conclusion: the compiler generates as many variants of the function as there are ways to call it in the program.

 

4. How many generic data types it is possible to define for a template function?

If necessary, in the template function any number of generic types can be defined (two, three, etc.). In this case, generic types are listed separated by commas using the keywords ‘class’ or ‘typename’.

For example. For the two types with the names T1, T2, the template function will have the following general form

template <class T1, class T2>
return_type FunName(list_of_parameters)
{
    // ...
}

where

  • return_type – the type that the function returns;
  • Fun_Name – the name of template function;
  • list_of_parameters – parameters of the template function, which operates with generic types T1, T2.

 

5. An example of a template function that contains two general types

Below is an example of a template function that uses two generic types T1, T2. The function receives two parameters of types T1, T2 and displays the value of these parameters on the screen. To declare types, use the keyword typename. You can also use the ‘class’ keyword.

#include "stdafx.h"
#include <iostream>
using namespace std;

// Template function that outputs the values of t1, t2
template <typename T1, typename T2>
void Display(T1 t1, T2 t2)
{
    cout << "t1 = " << t1 << "; t2 = " << t2 << endl;
}

int main()
{
    int a = 30;
    double d = 9.83;
    char c = 'X';
    bool b = true;

    Display(a, d); // t1 = 30; t2 = 9.83
    Display(b, c); // t1 = 1; t2 = X
    Display(8, -100); // t1 = 8; t2 = -100

    return 0;
}

 

6. What is the explicit specialization of a template function? Example

Template specialization of a template function is the declaration of another function with the same name, but for a specific type (for example, int, double). Thus, the specialized function replaces the template (generalized) function for some specific case (data type). For other cases, a generic version of the template function is called.

Example. In the example, the Display() template function is specialized for the string type. Such an specialization is logically correct, since the cout operator cannot output the string type in the usual way.

cout << "t = " << t << endl;

In this case, there will be a compilation error, since the string type requires a conversion from t.c_str() to const char* type. Such conversion is implemented in the “overloaded” Display() function, which receives a variable t of type string.

#include "stdafx.h"
#include <iostream>
using namespace std;

// template function of type T
template <class T>
void Display(T t)
{
    cout << "t = " << t << endl;
}

// explicit specialized function Display() for string type
void Display(string t)
{
    // output of string type is highlighted by a separate function
    cout << "t = " << t.c_str() << endl;
}

int main()
{
    int a = 10;
    double d = 3.55;
    string s = "Hello";

    // call of template function
    Display(a); // t = 10
    Display(d); // t = 3.55

    // call the "overloaded" function for string type
    Display("abcd"); // t = abcd
    Display(s); // t = Hello

    return 0;
}

 

7. What does the overloading of template function mean? Example

The “overloading” of the template function should not be confused with the explicit specialization of the template function (see p. 6). The overloading of a template function is the use of the same name for a template function, but with a different number of parameters.

Example. Below is the overloading of the Max() template function, which finds the maximum value between two, three, and four values of the generic type T.

#include "stdafx.h"
#include <iostream>
using namespace std;

// template function Max() fot type T,
// which returns maximum between value1 and value2
template <typename T>
T Max(T value1, T value2)
{
    if (value1 > value2) return value1;
    return value2;
}

// "overloaded" template function Max()
// it returns maximum between value1, value2, value3
template <class T>
T Max(T value1, T value2, T value3)
{
    T max = value1;
    if (max < value2) max = value2;
    if (max < value3) max = value3;
    return max;
}

// "overloaded" template function Max()
// maximum between four values
template <typename T>
T Max(T value1, T value2, T value3, T value4)
{
    T max = value1;
    if (max < value2) max = value2;
    if (max < value3) max = value3;
    if (max < value4) max = value4;
    return max;
}

int main()
{
    // using overladed template function Max()
    int i;
    double d;
    bool b;
    char c;

    // for type int
    i = Max(8, 11); // i = 11
    i = Max(9, 13, 14); // i = 14
    i = Max(8, 10, 4, -3); // i = 10

    // for type double
    d = Max(3.5, 1.2); // d = 3.5
    d = Max(1.3, -9.20, 100.33); // d = 100.33
    d = Max(-39.5, 8.82, 1.23); // d = 8.82

    // for type bool
    b = Max(true, false); // b = 1

    // for type char
    c = Max('C', 'F'); // c = 'F'
    c = Max('F', 'H', 'G'); // c = 'H'
    c = Max('M', 'A', 'X', 'W'); // c = 'X'
    
    return 0;
}

 

8. How can standard and generic parameters be used in a template function? Example

The template function is allowed to use standard parameters. These parameters are declared in the same way as for a regular non-template function.

Example. The Mult() function is implemented, which adds a specified number of times the value of a generic parameter of type T. The number of additions is set by the integer count. The function returns the result that is the sum of the parameters of type T.

The example demonstrates the use of the function for the types int and double. For other types, it is necessary to define explicitly “overloaded” implementations of the Mult() function.

#include "stdafx.h"
#include <iostream>
using namespace std;

// a function that adds the 'value' a specified number of times
// the function receives the integer value of the input parameter
template <class T>
T Mult(T value, int count)
{
    T res = value;
    for (int i = 1; i < count; i++)
    {
        res = res + value;
    }
    return res;
}

int main()
{
    // using of the template function Mult()
    int i;
    double d;
    string s;

    // for type int
    i = Mult(5, 2); // i = 10
    i = Mult(6, 4); // i = 24

    // for type double
    d = Mult(3.5, 3); // d = 10.5
    d = Mult(6.2, 8); // d = 49.6

    return 0;
}

 

9. An example of a template function that implements the sorting using “bubble” method

The example implements the template function Sort(), which sorts an array of elements of the generalized type T. The function receives the parameter reference to the array and the number of elements in the array. The main() function demonstrates the use of the Sort() template function.

#include "stdafx.h"
#include <iostream>
using namespace std;

// template function that sorts an array of numbers in descending order
template <class T>
void Sort(T A[], int count)
{
    int i, j;
    T tmp;
    for (i=0; i<count-1; i++)
        for (j=i; j>=0; j--)
            if (A[j] < A[j + 1])
            {
                // swap values A[j] and A[j+1]
                tmp = A[j];
                A[j] = A[j + 1];
                A[j + 1] = tmp;
            }
}


int main()
{
    // use of Sort() function
    int M[] = { 3, 5, -1, 2, -9, 7, 8, 3 };
    double D[] = { 3.3, 2.8, 1.5, 4.8, 6.1, 1.3 };

    // for int type
    Sort(M, 8); // M = { }

    for (int i = 0; i < 8; i++)
        cout << M[i] << ", ";

    cout << endl << endl;

    // for double type
    Sort(D, 6);
    for (int i = 0; i < 6; i++)
        cout << D[i] << ", ";

    return 0;
}


Related topics