C++ Core Guidelines: Interfaces I

Interfaces are a contract between a service provider and a service consumer. The C++ Core Guidelines has 20 rules to make them right because "interfaces is probably the most important single aspect of code organization".


Lego dimensions.svg

Before I dive into the rules, here is an overview of the 20 rules.

I will make my discussion of the rules not so elaborated because there are too many rules. My idea is that I write in this post about the first ten rules and in the next post about the remaining 10. So, let's start.

I.1: Make interfaces explicit

This rule is about correctness and means: assumptions should be stated in an interface. Otherwise, they are easily overlooked and hard to test.

int round(double d)
    return (round_up) ? ceil(d) : d;    // don't: "invisible" dependency


For example, the function round does not express that its result depends on the invisible dependency round_up.

I.2: Avoid global variables

This rule is kind of obvious but the emphasis lies on mutable global variables. Global constants are fine because they cannot introduce a dependency into the function and cannot be subject to race conditions.

I.3: Avoid singletons

Singletons are global objects under the hood, therefore, you should avoid them.

I.4: Make interfaces precisely and strongly typed

The reason for this rule makes it clear: "Types are the simplest and best documentation, have a well-defined meaning, and are guaranteed to be checked at compile time."

Have a look at an example:

void draw_rect(int, int, int, int);   // great opportunities for mistakes
draw_rect(p.x, p.y, 10, 20);          // what does 10, 20 mean?

void draw_rectangle(Point top_left, Point bottom_right);
void draw_rectangle(Point top_left, Size height_width);

draw_rectangle(p, Point{10, 20});  // two corners
draw_rectangle(p, Size{10, 20});   // one corner and a (height, width) pair


How easy is it to use the function draw_rect in the incorrect way? Compare this to the function draw_rectangle. The compiler guarantees that the argument is either a Point or a Size object.

You should, therefore, look in your process of code improvement for functions with many built-in type arguments and even worse, for functions that accept void* as a parameter.

I.5: State preconditions (if any)

If possible, preconditions such that x in double sqrt(double x) must be non-negative, should be expressed as assertions.

Expects() from the Guideline support library (GSL) let you express your precondition directly.

double sqrt(double x) { Expects(x >= 0); /* ... */ }


Contracts, consisting of preconditions, postconditions, and assertions may be part of the next C++20 standard. See the proposal p03801.pdf.

I.6: Prefer Expects() for expressing preconditions

That is similar to the previous rule, but the emphasis is on a different aspect. You should use Expects() for expressing preconditions and not, for example, an if expression, a comment, or an assert() statement. 

int area(int height, int width)
    Expects(height > 0 && width > 0);            // good
    if (height <= 0 || width <= 0) my_error();   // obscure
    // ...


The expression Expects() is easier to spot and maybe checkable by the upcoming C++20 standard.

I.7: State postconditions, I.8: Prefer Ensures() for expressing postconditions

In accordance with the arguments of a function, you have to think about its results. Therefore, the postcondition rules are quite similar to previous precondition rules.

I.9: If an interface is a template, document its parameters using concepts

We will get with high probability with C++20 concepts. Concepts are predicates on template parameters that can be evaluated at compile time. A concept may limit the set of arguments that are accepted as template parameters. I already wrote four posts about concepts, because there is a lot more to concepts.

The rule of the C++ Core Guidelines is quite easy. You should apply them.

template<typename Iter, typename Val>
requires InputIterator<Iter> && EqualityComparable<ValueType<Iter>>, Val>
Iter find(Iter first, Iter last, Val v)
    // ...


The generic find algorithm requires that the template parameter Iter is an InputIterator and the underlying value of the template parameter Iter is EqualityComparable. If you invoke the find algorithm with a template argument that does not satisfy this requirement, you will get a readable and easy to understand the error message.

I. 10: Use exceptions to signal a failure to perform a required task

Here is the reason: "It should not be possible to ignore an error because that could leave the system or a computation in an undefined (or unexpected) state."

The rule provides a bad and a good example.

int printf(const char* ...);    // bad: return negative number if output fails

template <class F, class ...Args>
// good: throw system_error if unable to start the new thread
explicit thread(F&& f, Args&&... args);


In the bad case, you can ignore the exception and your program has undefined behaviour.

If you can't use exceptions, you should return a pair of values. Thanks to C++17 feature structured binding, you can do it quite elegantly.

auto [val, error_code] = do_something();
if (error_code == 0) {
    // ... handle the error or exit ...
// ... use val ...


What's next?

That is quite easy to guess. In the next post, I write about the remaining rules to pointers, initialisation of globals objects, function parameters, abstract classes, and ABI (application binary interface)? There is a lot to know about good interface design.


Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, Marko, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, espkk, Louis St-Amour, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Neil Wang, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Tobi Heideman, Daniel Hufschläger, Red Trip, Alexander Schwarz, Tornike Porchxidze, Alessandro Pezzato, Evangelos Denaxas, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Dimitrov Tsvetomir, Leo Goodstadt, Eduardo Velasquez, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, and Michael Young.


Thanks in particular to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, and Bhushan Ivatury.



My special thanks to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small



I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

Bookable (Online)


Standard Seminars (English/German)

Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.


Contact Me

Modernes C++,





My Newest E-Books

Course: Modern C++ Concurrency in Practice

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

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Interactive Course: The All-in-One Guide to C++20

Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code


Today 1796

Yesterday 7541

Week 24722

Month 194139

All 7461979

Currently are 159 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments