C++ Basic templates usage – Part 2
Tags: cpp, metaprogramming, development, templates
Published: 2020-08-20 19:27:04

---
title: C++ Basic templates usage – Part 2
published: true
date: 2020-07-30 14:21:53 UTC
tags: cpp,metaprogramming,development,templates
canonical_url: https://cppsenioreas.wordpress.com/2020/07/30/cpp-basic-templates-usage-part-2/
---

_This is the third article in the series of meta programming tutorials. Here we’ll see more basic usage of templates in C++. In this part I’ll talk about non-type template parameters, template of templates, and about passing a function as a template argument._

<strong>Next post on series:</strong> [C++ templates – Beginners most common issue](https://cppsenioreas.wordpress.com/2020/08/02/cpp-templates-beginners-most-common-issue/)

<h1>Non-Type Template Parameters</h1>

<p>So far we saw a type template parameter, which is basically means that the function/class specializations are differed by a type/s that passed as a template parameter/s (e.g. int, float, double, std::string, etc...). So what does a non-type template parameter means?</p>

<p>A template that accepts  one of the following types:</p>

<ul>
<li>lvalue reference</li>
<li>nullptr_t</li>
<li>pointer</li>
<li>enumerator</li>
<li>integral</li>
</ul>

<h2><strong>Integral</strong></h2>

<p><strong>std::array</strong></p>

<p>Probably the most famous usage for a non-type template parameter is for std::array. std::array accepts two template parameters: array type (type parameter) &amp; array size (non-type parameter). Example:</p>

```cpp
std::array<int, 5> arr;
```

<p>As you can see, the array size is defined at compile time, and can't be changed during run-time. It might get annoying when you try to create a function that accept the arrays you are working with, when the arrays are deffer in their sizes:</p>

```cpp
void my_array_func(std::array&lt;int, 5> &amp;arr); // Accepts integer arrays with size 5.
void my_array_func(std::array&lt;int, 6> &amp;arr); // Accepts integer arrays with size 6.
void my_array_func(std::array&lt;int, 7> &amp;arr); // Accepts integer arrays with size 7.
```

<p>To go around this issue, we should use a non-type template parameter in this function:</p>

```cpp
template <size_t N>
void my_array_func(std::array<int, N> &arr); // Accepts any integers array.
```

<p>Or even in a more generic way:</p>

```cpp
template <typename T, size_t N>
void my_array_func(std::array<T, N> &arr); // Accepts any array.
```

<p><strong>Compile-Time Mathematics Expressions</strong></p>

<p>Another famous use-case for non-type template parameter are compile-time mathematics expressions calculation.</p>

```cpp
namespace math {
    
    /* Factorial */
    template <size_t N>
    struct factorial {
        static constexpr auto val = N * factorial<N - 1>::val;
    };

    template <>
    struct factorial<1> { // Partial specialization will be discuss in a future post in this series
        static constexpr auto val = 1;
    };

    /* Pow */
    template <size_t Base, size_t N>
    struct pow {
        static constexpr auto val = Base * pow<Base, N - 1>::val;
    };

    template <size_t Base>
    struct pow<Base, 0> { // Partial specialization will be discuss in a future post in this series
        static constexpr auto val = 1;
    };
}

int main() {
    std::cout << math::factorial<5>::val << std::endl; // Output 120
    std::cout << math::pow<2, 10>::val << std::endl;   // Output 1024
    return EXIT_SUCCESS;
}
```

<p>The important thing to understand, is that from run-times perspective, the above main would be equivalent to the following one:</p>

```cpp
int main() {
    std::cout << 120 << std::endl;
    std::cout << 1024 << std::endl;
    return EXIT_SUCCESS;
}
```

<p>Let's take the factorial for example to explain how does it work:</p>

* At first, the compiler instantiate `math::factorial<5>`, but to complete it's val, it should take `math::factorial<5 - 1>`.

* The compiler instantiate `math::factorial<4>`, but to complete it's val, it should take `math::factorial<4 - 1>`.

* The compiler instantiate `math::factorial<3>`, but to complete it's val, it should take `math::factorial<3 - 1>`.

* The compiler instantiate `math::factorial<2>`, but to complete it's val, it should take `math::factorial<2 - 1>`.

* `factorial<1>` already specialized, so the recursion can now collapse.

* `factorial<2>::val` is `2 * factorial<1>::val`, which is equal to `2`.

* `factorial<3>::val` is `3 * factorial<2>::val`, which is equal to `6`.

* `factorial<4>::val` is `4 * factorial<3>::val`, which is equal to `24`.

* `factorial<5>::val` is `5 * factorial<4>::val`, which is equal to `120`.

<h2><strong>Enumerator</strong></h2>

<p>The following is a simple example, to print enum values at compile time:</p>

```cpp
enum languages {
    CPP,
    C,
    CSHARP,
    JAVA,
    ASSEMBLY
};

template <languages Lang>
constexpr auto stringify() {
    if constexpr (Lang == CPP) {
        return "C++ language";
    } else if constexpr (Lang == C) {
        return "C language";
    } else if constexpr (Lang == CSHARP) {
        return "C# language";
    } else if constexpr (Lang == JAVA) {
        return "Java language";
    } else if constexpr (Lang == ASSEMBLY) {
        return "Assembly language";
    }
}

int main() {
    std::cout << stringify<CPP>(); // C++ language
    return EXIT_SUCCESS;
}
```

<h2><strong>Pointers</h2></strong>

<p>You can send pointer as a non-type template parameter, as long as it's address is known at compile-time. It's true for static variables:</p>

```cpp
template<int* T>
int func(int t) {
    return (*T)++ + t;
}

int main() {
    static int a = 6;
    std::cout << func<&a>(6) << std::endl; // Prints 12
    std::cout << func<&a>(6) << std::endl; // Prints 13
    
    return EXIT_SUCCESS;
}
```

<p>Template pointers are usually used to pass another member function as an interface to a class/function:</p>

```cpp
class general_class {
public:
    void func1() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    void func2() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

template<typename T, void (T::*interface)()> // The interface requires a function which returns void and accepts no params.
class interface_required {
public:
    interface_required(T* object) : object(object) {}
    void func() {
        (object->*interface)();
    }

private:
    T *object;
};
```

<p>Now we can call `interface_required` with both of `general_class` function, a single function per instance:</p>

```cpp
int main() {
    general_class gc;
    interface_required<general_class, &general_class::func1> ir(&gc);
    interface_required<general_class, &general_class::func2> ir2(&gc);
    ir.func(); // void general_class::func1()
    ir2.func(); // void general_class::func2()

    return EXIT_SUCCESS;
}
```

<p>Another advantage of this usage is that there is less overhead in the call to this object's function. It's like calling a function and not to a member function.</p>

<h2><strong>lvalue reference</h2></strong>

<p>The same rule for pointers also applied here- the variable address should be known at compile-time.</p>

```cpp
template<int& T>
int func(int t) {
    return T++ + t;
}

int main() {
    static int a = 6;
    std::cout << func<a>(6) << std::endl; // Prints 12
    std::cout << func<a>(6) << std::endl; // Prints 13

    return EXIT_SUCCESS;
}
```

<h2><strong>nullptr_t</h2></strong>

<p>we we'll discuss this in a future post, it's part of more advanced meta-programming topic.</p>

<h1>Template of Templates</h1>

<p>An important thing to mention, is that this ability usually doesn't really necessary to use, however it might make to code easier to write and to understand, so don't avoid a friendship with it.</p>

<p>Sometimes, especially when writing a library, it's important to make the code as generic as possible, and we don't want to limit library users to use a specific container type (e.g. std::vector, std::set, std::list, etc..). There are many ways to archive this generic target, and the following example is one of them:</p>

```cpp
#include <numeric>
#include <vector>

template <typename Cont>
auto sum(Cont &container) {
    typedef typename Cont::value_type T;
    return std::accumulate(std::begin(container), std::end(container), T(0));
}

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5, 6};
    int res = sum(vec); // Use compiler deduction
    // int res = sum<std::vector<int>>(vec);
    return EXIT_SUCCESS;
}

```

<p>It worked, and I'll expend the talk about `auto` in a future post in this series (for now it's a type that deduced at compile time by it's first usage). But there is a line that made this simple code to a very unpleasant:<br>`typedef typename Cont::value_type T;`<br>It seems that there have to be a better way to get this type. Let's use template of templates:</p>

```cpp
#include <numeric>
#include <vector>

template <typename T, template<typename, typename = std::allocator<T>> class Cont> // Since C++17 the class can be also a typename
T sum(Cont<T> &container) {
    return std::accumulate(std::begin(container), std::end(container), T(0));
}

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5, 6};
    int res = sum(vec); // Use compiler deduction
    // int res = sum<std::vector, int>(vec);
    return EXIT_SUCCESS;
}
```

<p>This line disappeared and we still got the same result. So all we have to do now is to inspect the template line:</p>

```cpp
template <typename T, template<typename, typename = std::allocator<T>> class Cont>
```

`typename T` - will represent the type that the container will contain.<br>`template<typename, typename = std::allocator<T>>` - The first type will accept our `T`, and the second is required for the standard library (std) containers, and by default (which we'll use) is the standard allocator of T (as we do most of the times we use the standard containers.<br>`class Cont` - It's the name of the template param type. Until C++17, we had to use the `class` keyword for these cases of templates-templates, however since C++17 we can still use `typename` as following:

```cpp
template <typename T, template<typename, typename = std::allocator<T>> typename Cont>
```

<p>Most of the necessary usages of templates-templates is on structs/classes with variadic template parameters (don't panic!), but here is a rare case when you have to use it on function:</p>

```cpp
template <typename OutContType, template <typename, typename> class C, typename InContType>
auto cast_all(const C<InContType, std::allocator<InContType>> &c) {
    C<OutContType, std::allocator<OutContType>> result(c.begin(), c.end());
    return result;
}

int main() {
    std::vector<double> double_vec = {1.5, 2.3, 3.6};
    std::vector<int> int_vec;
    int_vec = cast_all<int>(double_vec);
    // cast_all<int, std::vector, double>(double_vec);
    return EXIT_SUCCESS;
}
```

<p>A simple casting from one container type to the same container of another type, and you have to pass the container as template of template, or else you won't be able to use the container for another type.</p>

<p>A simplification of this function I'll show in a future post about variadic template parameters.</p>

<h1>Passing Function as a Template Argument</h1>

<p>This section is only a spoiler for a future post about variadic template parameters, just to prepare you to this subject.</p>

<p>Passing function pointer to another function is something that came all the way from the procedural C language:</p>

```cpp
void qsort (void* base,
            size_t num,
            size_t size,
            int (*comparator)(const void*,const void*));
```

<p>In C++, since C++11 (or using boost::function for earlier C++ versions), there is std::function that make the syntax more readable:</p>

```cpp
std::function<int(void*, void*)> &&comparator
```

<p>The main issue with this call is the performances. There is an overhead when calling a function with a std::function parameter. To avoid this overhead, we can pass a function as a template parameter:</p>

```cpp
template<typename FuncT>
int max(std::vector<int> vec, FuncT &&comparator) {
    int res = vec[0];
    for (auto &elem : vec)
        if (comparator(res, elem) < 0)
            res = elem;
    return res;
}
```

<p>Now that we have a generic fucntion parameter, let's make out function generic too:</p>

```cpp
template<typename Cont, typename FuncT>
auto max(Cont container, FuncT &&comparator) {
    auto res = *std::begin(container);
    for (auto &elem : container)
        if (comparator(res, elem) < 0)
            res = elem;
    return res;
}

int main() {
    std::vector<int> int_vec = {1, 30, 20, 10};
    std::list<double> double_list = {5.2, 2.9, 6.3, 4.8};
    // Since C++20 template params are allowed in lambda expressions. Since C++14 we can also use `auto`, but here `auto` is too generic for this function.
    auto comp = [] <typename T> (T n1, T n2) -> auto {
        return n1 - n2;
    };
    std::cout << max(int_vec, comp) << std::endl;
    std::cout << max(double_list, comp) << std::endl;
    return EXIT_SUCCESS;
}
```

<h1>Conclusion</h1>

<p>I hope you learned something new from the second part of basic generic usage of templates. From now on we are going deeper into the meta-programming subjects, and we'll see more abilities and more usages of meta-programming in modern C++.</p>

<p>Have something unclear? A request for a future post? Want to share new things you learned? Feel free to share!</p>

This post originally published on my personal blog: [C++ Senioreas](https://cppsenioreas.wordpress.com/).