C++ Core Guidelines: Template Definitions

Template definitions deal with guidelines that are specific to a template implementation. This means, in particular, these rules focus on how a template definition depends on its context.

 super charged engine 2770374 1280

 Here are today's rules for template definitions:

The first rule is quite special.

T.60: Minimize a template’s context dependencies

Honestly, it took me a few moments to get this rule. Let's look at the function templates sort and algo. Here is a simplified example of the guidelines.

template<typename C>
void sort(C& c)
{
    std::sort(begin(c), end(c)); // necessary and useful dependency
}

template<typename Iter>
Iter algo(Iter first, Iter last) {
    for (; first != last; ++first) {
        auto x = sqrt(*first); // potentially surprising dependency: which sqrt()?
        helper(first, x);      // potentially surprising dependency:
                               // helper is chosen based on first and x    
}

 

It would be optimal but not always manageable if a template operates only on its arguments. This holds for the function template sort but not for algo.The function template algo has dependencies to sqrt and to the function helper. At the end, the implementation of algo introduces more dependencies than the interface shows.

T.61: Do not over-parameterize members (SCARY)

If a member of a template does not depend on a template parameter remove it from the template. A member may be a type or a method. By following this rule you may decrease the code size because the non-generic code is factored out.

The example from the guidelines is quite straightforward.

template<typename T, typename A = std::allocator{}>
    // requires Regular<T> && Allocator<A>
class List {
public:
    struct Link {   // does not depend on A
        T elem;
        T* pre;
        T* suc;
    };

    using iterator = Link*;

    iterator first() const { return head; }

    // ...
private:
    Link* head;
};

List<int> lst1;
List<int, My_allocator> lst2;

 

The type Link does not depend on the template parameter A. So I can remove it and use it in List2.

template<typename T>
struct Link {
    T elem;
    T* pre;
    T* suc;
};

template<typename T, typename A = std::allocator{}>
    // requires Regular<T> && Allocator<A>
class List2 {
public:
    using iterator = Link<T>*;

    iterator first() const { return head; }

    // ...
private:
    Link* head;
};

List<int> lst1;
List<int, My_allocator> lst2;

 

This was an easy job? Yes? No! The title of this rule writes about SCARY. What does that mean? I'm at least curious but to be honest, you can ignore the next lines.

The acronym SCARY describes assignments and initializations that are Seemingly erroneous (appearing Constrained by conflicting generic parameters), but Actually work with the Right implementation (unconstrained bY the conflict due to minimized dependencies).

I hope, you get it for the details see N2911. In order not to bore you, here is the obvious idea applied to the standard container iterator: they have no dependency to the container's, key_compare, hasher, key_equal, or allocator types.

The next rule helps to reduce code bloat.

T.62: Place non-dependent class template members in a non-templated base class

Let me say it more informal: put the functionality of the template which does not depend on the template parameters in a non-templated base class.

The guidelines present a quite obvious example.

template<typename T>
class Foo {
public:
    enum { v1, v2 };
    // ...
};

 

The enumeration is independent of the type parameter T and should, therefore, be placed in a non-templated base class.

struct Foo_base {
    enum { v1, v2 };
    // ...
};

template<typename T>
class Foo : public Foo_base {
public:
    // ...
};

 

Now, Foo_base can be used without template arguments and template instantiation.

This technique is quite interesting if you want to reduce your code size. Here is a simple class template Array.

 

// genericArray.cpp

#include <cstddef>
#include <iostream>

template <typename T, std::size_t N>
class Array{
public:
    Array()= default;
    std::size_t getSize() const{
        return N;
    }
private:
  T elem[N];
};

int main(){

    Array<int, 100> arr1;
    std::cout << "arr1.getSize(): " << arr1.getSize() << std::endl;

    Array<int, 200> arr2;
    std::cout << "arr2.getSize(): " << arr2.getSize() << std::endl;
    
}

 

If you study the class template Array, you will see that the method getSize is the same except for type parameter N. Let me refactor the code and declare a class template Array which depends on the type parameter T.

 

// genericArrayInheritance.cpp

#include <cstddef>
#include <iostream>


template<typename T>
class ArrayBase {
protected:
    ArrayBase(std::size_t n): size(n) {} 
    std::size_t getSize() const {
        return size;
    };
private:
    std::size_t size;
};

template<typename T, std::size_t n>
class Array: private ArrayBase<T>{
public:    
    Array(): ArrayBase<T>(n){}
    std::size_t getSize() const {
        return  ArrayBase<T>::getSize();
    }
private:
    T data[n]; 
};   


int main(){

    Array<int, 100> arr1;
    std::cout << "arr1.getSize(): " << arr1.getSize() << std::endl;

    Array<int, 200> arr2;
    std::cout << "arr2.getSize(): " << arr2.getSize() << std::endl;
    
}

 

Array has two template parameters for the type T and the size n but ArrayBase only one template parameter for the type T. Array derives from ArrayBase. This means ArrayBase is shared between all instantiations of Array which uses the same type T. In the concrete case, the getSize method of Array uses the getSize method of ArrayBase.

Thanks to CppInsight, I can show you the compiler generated code.

Here is the instantiation of ArrayBase<int>:

ArrayBase

And here the instantiation for Array<int, 100> and Array<int, 200>:

Array

Array200

 

 

 

 

 

 

 

 

 

 

What's next?

Of course, there are more rules left to template definitions. So my story continues with the next post. I hope my explanation to template definitions are good enough because I know many programmers are scared of templates. To me, the ideas of templates are easy to get, but the syntax has still potential.

 

 

 

 

Thanks a lot to my Patreon Supporters: Eric Pederson, Paul Baxter,  Meeting C++, Matt Braun, Avi Lachmish, Roman Postanciuc, Venkata Ramesh Gudpati, Tobias Zindl, Dilettant, Marko, Ramesh Jangama, and Emyr Williams.

 

Thanks in particular to:  TakeUpCode 450 60

 

Get your e-book at Leanpub:

The C++ Standard Library

 

Concurrency With Modern C++

 

Get Both as one Bundle

cover   ConcurrencyCoverFrame   bundle
With C++11, C++14, and C++17 we got a lot of new C++ libraries. In addition, the existing ones are greatly improved. The key idea of my book is to give you the necessary information to the current C++ libraries in about 200 pages.  

C++11 is the first C++ standard that deals with concurrency. The story goes on with C++17 and will continue with C++20.

I'll give you a detailed insight in the current and the upcoming concurrency in C++. This insight includes the theory and a lot of practice with more the 100 source files.

 

Get my books "The C++ Standard Library" (including C++17) and "Concurrency with Modern C++" in a bundle.

In sum, you get more than 600 pages full of modern C++ and more than 100 source files presenting concurrency in practice.

 

Get your interactive course

 

Modern C++ Concurrency in Practice

C++ Standard Library including C++14 & C++17

educative CLibrary

Based on my book "Concurrency with Modern C++" educative.io created an interactive course.

What's Inside?

  • 140 lessons
  • 110 code playgrounds => Runs in the browser
  • 78 code snippets
  • 55 illustrations

Based on my book "The C++ Standard Library" educative.io created an interactive course.

What's Inside?

  • 149 lessons
  • 111 code playgrounds => Runs in the browser
  • 164 code snippets
  • 25 illustrations

Add comment


Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code

Visitors

Today 1887

All 1492064

Currently are 179 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments