C++ Function Templates with Examples

By , last updated November 8, 2017

In this tutorial we will give an introduction to C++ function templates and provide simple function template examples and a more complex sort predicates example with generic sorting template function.

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;
is_even(i64_val);

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

Simple Function Template Example

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

is_even(int_val);
is_even(i64_val);

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.

Member of a Non-template Class Example

Function templates have two faces. Either they are a member of a non-template class, or they are free functions in the global or some namespace.

These are a member of a non-template class, with function templates. Here’s a simple example:

// filename: interface.hpp
class interface
{
protected:
	template<typename RESULTS, typename DATA>
	void insert(RESULTS &results, const DATA &data);
}
// filename: interface.cpp

#include "interface.hpp"

// Full specialization
template<>
void interface::insert<>( Results &results, const Data &data )
{
	// do stuff
}

Function Template Sort Example

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
    generic_sort(numbers);

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

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

If you need more functionality that would best fit as a Class which is parameterised by a type, you may consider creating a C++ Class Template.

Senior Software Engineer developing all kinds of stuff.

Comments

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>

*