Templates on the surface

By , last updated August 14, 2019

Templates is an important part of the C++ language. Templates is a language within the language. There are two kinds of templates, one is function templates and the other is template classes. This chapter will only go through the basic usage and explanations.

A fun fact about templates, is that C++ templates are Turing complete. If something is Turing complete, it can be used to compute any problem solved by computation.

In other languages like Java and C# templates are called generics. In C++ those are called templates and templates are the second most important feature in C++ (with destructors being the most important feature).

The concept of generic programming is to write code once, and this code will be valid for all intended types. For basic methods, a beginner will think it’s OK to write overloads for all types, for the same algorithm. But that’s really the hard way (and not very smart) of doing things.

It was possible to write generic code before templates in C and pre-template C++, but that was not type-safe. A generic sort method could only accept void* parameters, and it had to know the size of each element, how many elements to sort over and a predicate. Every interface had to be void* because there were no language feature to ensure type safety. If you sorted ints, the predicate must be int. If you sorted longs, the predicate must be long.

Due to legacy reasons, those interfaces using void* are available, but new code shouldn’t use those at all.

Here is a prime example on how the situation was before templates came along (and still is in C).

// Please do not use this code. It's very inefficient and error prone.
#include <stdlib.h>
#include <search.h>

// Predicate
int compare_ints(const void * a, const void * b)
{
    // Cast to int* from void*, then deference to int
    int val1 = *((int*)a);  
    int val2 = *((int*)b);

    // Predicate should return 0 if identical
    if (val1 == val2) 
        return 0;

    // -1 for less than, 1 for greater than
    return (val1 < val2) ? -1 : 1;
}

void sort_ints()
{
#define NUM_INTS 10
    int arr[NUM_INTS];

    // Create a reverse list of ints from 10 to 1
    for (int i = 0; i < NUM_INTS; ++i)
    {
        arr[i] = NUM_INTS - i;
    }

    // Sort
    qsort(&arr, NUM_INTS, sizeof(int), &compare_ints);
}

Please do not use qsort in any new code, and do replace any occurrence of qsort with std::sort. And do only replace those occurrences you’re able to test. The interface is not identical between qsort and std::sort, so there may be corner cases where the actual order is not identical (with identical keys).

Here’s how to solve this particular example with class templates.

Function Templates

Tutorial about C++ Function Templates with examples.

Class Templates

Here’s a good C++ Class Templates Tutorial with simple and complex examples.

Specialized class templates

Specialized class templates description and examples.

Professional Software Developer, doing mostly C++. Connect with Kent on Twitter.