Tuesday Coding Tip 01 - C++ Concepts

posted Originally published at medium.com 2 min read

Tuesday coding tips are super short posts about various tidbits mainly from C++, but also from other programming languages I use. You can also follow the #TuesdayCodingTips hashtag on Mastodon and Linkedin.


Concepts are a C++20 feature that greatly simplifies templated code and allows you to build powerful type trait restrictions.

#include <concepts>

class Interface {
public:
    ~Interface() = default;
};

template<class T>
concept DerivedFromInterface = std::derived_from<T, Interface>;

// Note how 'class' or 'typename' is replaced with 'DerivedFromInterface'
template<DerivedFromInterface ObjectType>
void DoSomethingWith(ObjectType& object) {}

// Usage
class A final : public Interface {};
A a;
DoSomethingWith(a);

For example, you can create a function that accepts a concrete type that implements a certain interface, potentially allowing the compiler to optimize away the virtual table. Or you can define static interfaces where an object is required to have certain methods or even attributes, even if it doesn’t implement any inheritance-based interface. Or you can restrict the function to be called only with a small subset of well-known types.

#include <concepts>
#include <string>

template<class T>
concept Serializable = requires(T&& object)
{
    // Object has callable method 'serialize' which
    // returns something that works same as std::string
    { object.serialize()} -> std::same_as<std::string>;
};

template<Serializable T>
void UploadSerializable(const T& object)
{
    auto data = object.serialize();
    // ...
}

// Usage
class Settings {
public:
    std::string serialize() const { return ""; }
};

Settings settings;
UploadSerializable(settings);

Concepts do not replace dynamic polymorphism as you cannot do everything in compile-time. Still, it can open new optimization opportunities and help you write in-place construction functions like std::make_unique without an excessive amount of unreadable templates.

#include <concepts>
#include <string>
#include <memory>

// A function that accepts any string, disregarding if wide or narrow
template<typename T>
requires std::is_same_v<T, std::string> || std::is_same_v<T, std::wstring>
void DoSomethingWithAString(const T& str) {}

// A better implementation of make_unique which checks whether the
// object can be created from given arguments
template<class T, class ... Args>
requires std::constructible_from<T, Args...>
std::unique_ptr<T> make_unique(Args&& ... args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

Lastly, among the benefits to the syntax, they improve the compiler error messages, making life of your users way simpler.

More Posts

Tuesday Coding Tip 06 - Explicit template instantiation

Jakub Neruda - Apr 7

Tuesday Coding Tip 02 - Template with type-specific API

Jakub Neruda - Mar 10

Tuesday Coding Tip 05 - Object initialization in C++

Jakub Neruda - Mar 31

Your Tech Stack Isn’t Your Ceiling. Your Story Is

Karol Modelskiverified - Apr 9

I’m a Senior Dev and I’ve Forgotten How to Think Without a Prompt

Karol Modelskiverified - Mar 19
chevron_left

Related Jobs

View all jobs →

Commenters (This Week)

2 comments
1 comment
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!