DEV Community

Irfan
Irfan

Posted on • Updated on

C++ Template Meta Programming - The Basics

Template Meta-programming is a generic programming technique that uses extremely early binding to generate temporary source code, which is merged by the compiler with the rest of the source code and then compiled.
In order to completely understand why we need Template Programming, let's go back to Function Overloading.

Function overloading is somewhat tedious, because we have to essentially repeat the same code for each function but with different variable and parameter types. However, there is a way of avoiding this. There's a possibility of creating a recipe that will enable the compiler to automatically generate functions with various parameter types. The code defining the recipe for generating a particular group of functions is called a function template.

A function template has one or more type parameters , and we generate a particular function by passing a concrete type argument for each of the template's parameters. Thus, the functions generated by a function template all have the same basic code, but customized by the type arguments that we pass.

We will write an example using both function overloading and function template, that finds the largest element from an array.

int max(int max[], const int& len){
    int maximum(x[0]);
    for(int i = 0; i < len; ++i){
       if(maximum < x[i]) maximum = x[i];
    }
    return maximum;
}  

long max(long max[], const int& len){
    long maximum(x[0]);
    for(int i = 0; i < len; ++i){
       if(maximum < x[i]) maximum = x[i];
    }
    return maximum;
} 

double max(int max[], const int& len){
    double maximum(x[0]);
    for(int i = 0; i < len; ++i){
       if(maximum < x[i]) maximum = x[i];
    }
    return maximum;
} 
Enter fullscreen mode Exit fullscreen mode

The above example shows the three versions of one function using function overloading. We see that we have to repeat the same code for each version of the function.

Now let's define a function template for the same function max().

template<class T> T max(T x[], const int& len){
    T maximum(x[0]);
    for(int i = 0; i < len; ++i){
       if(maximum < x[i]) maximum = x[i];
    }
    return maximum;   
}
Enter fullscreen mode Exit fullscreen mode

The template keyword identifies this as a template definition. The angled brackets following the template keyword enclose the type parameters that are used to create a particular instance of the function separated by commas. In this instance we have one type parameter, T. The class keyword before the T indicates that the T is the type parameter for this template, class being the generic term for the type. Consequently, we have fundamental types in C++, such as type int and type char, and we also have types that we define. We can use the keyword typename instead of class to identify the parameters in a function template, in which case, the template definition would look like this:

template<typename T> T max(T x[], const int& len){
    T maximum(x[0]);
    for(int i = 0; i < len; ++i){
       if(maximum < x[i]) maximum = x[i];
    }
    return maximum;   
}
Enter fullscreen mode Exit fullscreen mode

The creation of a particular function instance is referred to as instantiation . Each time we use max() in our program, the compiler checks to see if a function corresponding to the type of arguments that we have used in the function call already exists. If the function required does not exist, the compiler creates one by substituting the argument type that we have used in our function call in place of the parameter T throughout the template definition.

Here's a full working example of function template.

#include <iostream>
#include <cstdlib>

template<typename T> T max(T x[], const int& len){
    T maximum(x[0]);
    for(int i = 0; i < len; ++i){
       if(maximum < x[i]) maximum = x[i];
    }
    return maximum;   
}

int main(){

int small[] = {1, 24, 34, 22};
long medium[] = {23, 245, 123, 1, 234, 2345};
double large[] = {23.0, 1.4, 2.456, 345.5, 12.0, 21.0};

int lenSmall(_countof(small)); //_countof() works only on MSVC.
int lenMedium(_countof(medium));
int lenLarge(_countof(large));

std::cout << max(small, lenSmall) << "\n";
std::cout << max(medium, lenMedium) << "\n";
std::cout << max(large, lenLarge) << "\n";

return 0;
}
Enter fullscreen mode Exit fullscreen mode

Examples:

Output :

34

2345

345.5

For each of the statements that output the maximum value in an array, a new version of max() is instantiated using the template. Of course, if you add another statement calling the function max() with one of the types used previously, no new version of the template code is generated.

Using the template doesn't reduce the size of your compiled program in any way. The compiler generates a version of the source code for each unique function that is required. In fact, using templates can generally increase the size of our programs, as functions may be created even though an existing version might satisfactorily be used by casting the argument. We can force the creation of particular instances of a template by explicitly including a declaration for it.

Template meta-programming allows the programmer to focus on architecture and delegate to the compiler the generation of any implementation required by client code. Thus, template meta-programming can accomplish truly generic code, facilitating code minimization and better maintainability.

Top comments (0)