Templates on the surface

By , last updated September 13, 2017

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).

We’ll get back to how to solve this particular example later.

Generic programming with function templates

You’re given the task of creating a method called is_even. This method will accept a number as input, and the result is true if the number is even.

The basic implementation will accept a number, and if successful return true. The most common way of checking if a number is even is to use the modulus operator. The modulus operator will return the remainder from a division 3 % 2 = 1, while 4 % 2 = 0. We can exploit this fact when implementing this method. A very basic implementation will look like this:

bool is_even(int a) 
    return (a % 2) == 0;

Calling this function with other types is allowed, but most compilers will issue a warning if you’re trying to call this method with a larger type than int. This code will issue a warning with warning level 2 (/W2) in Visual Studio and with -Wconversion with GCC.

#include <cstdint>

int64_t i64_val = 2;

// In Visual Studio:
// warning C4244: 'argument': conversion from 'int64_t' 
// to 'int', possible loss of data

// With GCC
// warning: conversion to 'int' from 'int64_t 
// {aka long int}' may alter its value [-Wconversion]

Binary representation of numbers in a computer

Some will argue this is a bad way of checking even-ness in a number. The modulus is per definition the remainder of a division operating, and division is much slower than addition and subtraction, and those are slower than checking bitness. Yes, it’s possible to check the LSB (least significant bit) on the number with 2 & 1 == 0. However, that is only true if and only if the number is an unsigned integer and/or the negative values are in two’s complement. With one’s complement, negative values will give the opposite result.

Value One’s complement Two’s complement
0 0000 0000
1 0001 0001
-1 1110 1111
2 0010 0010
-2 1101 1110

Table: 4-bit values in binary representation

As a C++ programmer, you can not assume your code will always execute on a two’s complement computer. It might happen your code will run on a totally different architecture, and this check will fail.

Using % 2 == 0 has no performance implications. It will be optimized away even in debug (by any compiler worth its salt).

A simple templated solution

With the previous detour in mind, the best and safe way of checking for a number to be even is to use % 2 == 0.

For an implementation accepting any number, of any type, the best way is to use templates. The benefits are tremendous, you write the algorithm, while the compiler has to figure out what type(s) to use.

Here is the answer:

template<typename T> 
bool is_even(T val)
    return val % 2 == 0;

All types of numbers are accepted by this implementation. There are no warnings and everything just works.

int int_val = 2;
int64_t i64_val = (1LL << 33);


This is what happens line by line. By starting the method with template, we’re letting the compiler know we want to use templates for this method. Next up is typename T. This means there is one type which can vary. The rest of the method is exactly like other non-template methods, with the notable exception of T instead of int. T is just a placeholder for the type the method is called with.

There are two ways of calling this templated method, either by implicit template deduction or explicit specification of the type. All methods are identical, unless there are non-template methods called is_even.

int val = 0;
is_even(val);       // Implicit template deduction
is_even<>(val);     // Implicit deduction
is_even<int>(val);  // Explicit specification

Using <> or <int> will only try to look for a match in templated methods. There are many rules to overload resolution, but those are out of scope for this chapter.

Function template sort

Up until now there has been much theory, but not much practice. Here is a real world example on how to use function templates to sort anything that can be sorted.

// Generic function sort
#include <iostream>     // std::cout
#include <vector>       // std::vector
#include <algorithm>    // std::sort

// Predicate
template<typename T>
bool sort_predicate(const T & a, const T & b)
    return a < b;

template<typename T>
void generic_sort(std::vector<T> & arr)
    // Sorting the arr vector with predicate sort_predicate
    std::sort(arr.begin(), arr.end(), &sort_predicate<T>);

void test_function_sort()
    // Vector of numbers
    std::vector<int> numbers = { 3,6,4,2,5,7,1 };

    // Sort numbers

    // Print numbers
    for (int number : numbers)
        std::cout << number << " ";

    // Output is:
    // 1 2 3 4 5 6 7

Class templates

Class templates are much like their sibling function templates. Class templates always start their definition with template. Since there is no way to overload classes, its not permitted to have several classes with the same name, templated or regular. Class templates are used when some functionality can’t be contained into one function. Some notable examples are std::vector and std::list. Because of class templates, it’s possible to have type safe containers. It also makes accidental mixing impossible. This code is illegal.

// Warning: Illegal code ahead
#include <vector>
#include <cstdint>

std::vector<int32_t> ints;
std::vector<int64_t> longs;

ints = longs;

From this illegal program, both Microsoft Visual C++ and GCC will emit errors.

// Error in Visual Studio
// Error C2679 binary '=': no operator found which takes a right-hand 
//   operand of type 'std::vector<int64_t,std::allocator<_Ty>>' '
//   (or there is no acceptable conversion)

// Error in GCC:
// error: no match for 'operator=' 
// (operand types are 'std::vector<int>' and 'std::vector<long int>')

The first class template

A class template starts with template and a number of arguments it can accept. This is a definition of a class template.

// Class template Foo
template<typename T> 
class Foo {};

// Class Bar
class Bar {};

This is a completely legal class template. It doesn’t do much, but when instantiating (using) the class, you must specify the type. This is explicit template instantiation.

// Use Foo with int and double, and Bar as a regular class.
Foo<int> foo;
Foo<double> foo_double;
Bar bar;

The name of the template argument can be almost anything, and there can be any number of template arguments. Though a class template with thousands of template arguments have a limited usability.

Making use of templates

The Foo class template above is not useful for anything. There are probably a few cases, but I’m not aware of any. Next up is to create a template, where the template argument is used for something.

template<typename T>
class Foo
        T data;

In this Foo, the member data is exactly the type T. You can instantiate Foo<T> with int or double. You can even instantiate Foo with your own classes and/or structures. There is really no limit to what T will accept. There are ways to limits what T will accept, but those techniques are reserved for more advanced chapters.

All of these are legal instantiations of the Foo above.

Foo<int>         foo1; // Plain old data
Foo<double>      foo2; // POD
Foo<std::string> foo3; // Foo with a string

class Bar {};
Foo<Bar> foo4;         // Foo with Bar
Foo<Foo<Bar>> foo5;    // Foo with a Foo with Bar

As you can see, templates are versatile and can be used for many things, not only regular data types such as int or double. What you can do with a regular class, you can do with a class template. But I did promise a real world example on class template.

Real world class template

This class and code snippet will be used to collect data, and when the data is collected, all data will be sorted and printed. All the work is done by the class template, and there is only one implementation of the class. There is not an implementation specific for integral numbers or custom structs. Templates are generic and can be used for anything a regular class is able to do.

// Generic class sort
#include <vector>
#include <string>
#include <iostream>

template<typename T>
class generic_class_sort {
        void add(const T &val) {

        void add(const std::initializer_list<T> & values)
            data.insert(data.end(), values);

        void sort() {
            // No predicate, use default predicate (std::less)
            std::sort(data.begin(), data.end());

        void print() {
            // Print all Ts
            for (const T & t : data)
                std::cout << t << " ";

            std::cout << "\n";

        std::vector<T> data;

void test_class_sort() {
    generic_class_sort<int> ints;
    ints.add({ 5,6,4,3,6,7,2,1 });

    // Output: 1 2 3 4 5 6 6 7

    generic_class_sort<std::string> strings;
    strings.add({ "e", "a", "d", "c", "f", "b" });

    // Output: a b c d e f

Specialized class templates

Specialized class templates description and examples.

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


Be the first to comment.

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>