2 Lines Of Code and 3 C++17 Features - The overload Pattern
Tags: cpp, cpp17, programming
Published: 2019-07-26 06:05:30

---
title: 2 Lines Of Code and 3 C++17 Features - The overload Pattern
published: true
description: See how the overload pattern works in C++17 and allows to pass multiple lambdas into std::visit.
tags: cpp, cpp17, programming
---

![the overload patter C++17](https://3.bp.blogspot.com/-vXolWEbJW7Q/XFbODfZzQ3I/AAAAAAAADpk/fu612OcMGY0VC6Txn6tdvwq3T6yMv40mgCLcBGAs/s1600/2lines3features.png)

While I was doing research for my book and blog posts about C++17 several times I stumbled upon this pattern for visitation of `std::variant`:

```cpp
template<class... Ts> struct overload : Ts... { using Ts::operator()...; };
template<class... Ts> overload(Ts...) -> overload<Ts...>;

std::variant<int, float> intFloat { 0.0f };
std::visit(overload(
        [](const int& i) { ... },
        [](const float& f) { ... },
    ),
    intFloat;
);
```

With the above pattern, you can provide separate lambdas “in-place” for visitation.

It’s just two lines of compact C++ code, but it packs a few interesting concepts.

Let’s see how this thing works and go through the three new C++17 features that enable this one by one.

Originally posted at [bfilipek.com](https://www.bfilipek.com/2019/02/2lines3featuresoverload.html)

## Intro

The code mentioned above forms a pattern called `overload` (or sometimes `overloaded`), and it’s mostly useful for `std::variant` visitation.

With such helper code you can write:

```cpp
std::variant<int, float, std::string> intFloatString { "Hello" };
std::visit(overload
  {
    [](const int& i) { std::cout << "int: " << i; },
    [](const float& f) { std::cout << "float: " << f; },
    [](const std::string& s) { std::cout << "string: " << s; }
  },
  intFloatString
);
```

The output:

    string: Hello

> Little reminder: `std::variant` is a helper vocabulary type, a discriminated union. As a so-called sum-type it can hold non-related types at runtime and can switch between them by reassignment `std::visit` allows you to invoke an operation on the currently active type from the given variant. Read more in my blog post [Everything You Need to Know About std::variant from C++17](https://www.bfilipek.com/2018/06/variant.html).

Without the overload you’d have to write a separate `class` or `struct` with three overloads for the `()` operator:

```cpp
struct PrintVisitor
{
    void operator()(int& i) const {
        std::cout << "int: " << i;
    }

    void operator()(float& f) const {
        std::cout << "float: " << f;
    }

    void operator()(std::string& s) const {
    std::cout << "string: " << s;
    }
};

std::variant<int, float, std::string> intFloatString { "Hello" };

std::visit(PrintVisitor(), intFloatString);
```

As you might already know the compiler conceptually expands lambda expression into a uniquely-named type that has `operator()`.

What we do in the overload pattern is that we create an object that inherits from several lambdas and then exposes their `operator()` for `std::visit`. That way you write overloads “in place”.

What are the C++17 features that compose the pattern?

*   Pack expansions in `using` declarations - short and compact syntax with variadic templates.
*   Custom template argument deduction rules - that allows converting a list of lambdas into a list of base classes for the `overloaded` class.
*   Extension to aggregate Initialization - the overload pattern uses a constructor to initialise, but we don’t have to specify it in the class. Before C++17 it wasn’t possible.

## New Features

Let’s explore section by section the new elements that compose the overload pattern. That way we can learn a few interesting things about the language.

### Using Declarations

There are three features here, but it’s hard to tell which one is the simplest to explain.

But let’s start with `using`. Why do we need it at all?

To understand that let’s write a simple type that derives from two base classes:

```cpp
#include <iostream>

struct BaseInt
{
    void Func(int) { std::cout << "BaseInt...\n"; }
};

struct BaseDouble
{
    void Func(double) { std::cout << "BaseDouble...\n"; }
};

struct Derived : public BaseInt, BaseDouble
{
    //using BaseInt::Func;
    //using BaseDouble::Func;
};

int main()
{
    Derived d;
    d.Func(10.0);
}
```

We have two bases classes that implement `Func`. We want to call that method from the derived object.

Will the code compile?

When doing the overload resolution set, C++ states that the Best Viable Function must be in the same scope.

So GCC reports the following error:

    error: request for member 'Func' is ambiguous

See a [demo here @Coliru](http://coliru.stacked-crooked.com/a/47c6fb7329caa19d)

That’s why we have to bring the functions into the scope of the derived class.

We have solved one part, and it’s not a feature of C++17\. But how about the variadic syntax?

The issue here was that before C++17 `using...` was not supported.

In the paper [Pack expansions in using-declarations P0195R2](https://wg21.link/P0195) - there’s a motivating example that shows how much extra code was needed to mitigate that limitation:

```cpp
template <typename T, typename... Ts>
struct Overloader : T, Overloader<Ts...> {
    using T::operator();
    using Overloader<Ts...>::operator();
    // […]
};

template <typename T> struct Overloader<T> : T {
    using T::operator();
};
```

In the example above, in C++14 we had to create a recursive template definition to be able to use `using`. But now we can write:

```cpp
template <typename... Ts>
struct Overloader : Ts... {
    using Ts::operator()...;
    // […]
};
```

Much simpler now!

Ok, but how about the rest of the code?

### Custom Template Argument Deduction Rules

We derive from lambdas, and then we expose their `operator()` as we saw in the previous section. But how can we create objects of this `overload` type?

As you know the type of a lambda is not know, so without the template deduction for classes, it’s hard to get it. What would you state in its declaration?

```cpp
overload<LambdaType1, LambdaType2> myOverload { ... } // ???
// what is LambdaType1 and LambdaType2 ??
```

The only way that could work would be some `make` function (as template deduction works for function templates since like always):

```cpp
template <typename... T>
constexpr auto make_overloader(T&&... t) {
   return Overloader<T...>{std::forward<T>(t)...};
}
```

With template deduction rules that were added in C++17, we can simplify the creation of common template types.

For example:

```cpp
std::pair strDouble { std::string{"Hello"}, 10.0 };
// strDouble is std::pair<std::string, double>
```

There’s also an option to define custom deduction guides. The Standard library uses a lot of them, for example for `std::array`:

```cpp
template <class T, class... U>  
array(T, U...) -> array<T, 1 + sizeof...(U)>;
```

and the above rule allows us to write:

```cpp
array test{1, 2, 3, 4, 5};
// test is std::array<int, 5>
```

For the overload patter we can write:

```cpp
template<class... Ts> overload(Ts...) -> overload<Ts...>;
```

Now, we can type

```cpp
overload myOverload { [](int) { }, [](double) { } };
```

And the template arguments for `overload` will be correctly deduced.

Let’s now go to the last missing part of the puzzle - aggregate Initialization.

### Extension to Aggregate Initialisation

This functionality is relatively straightforward: we can now initialise a type that derives from other types.

As a reminder: from [dcl.init.aggr](https://timsong-cpp.github.io/cppwp/n4659/dcl.init.aggr):

> An aggregate is an array or a class with  
> no user-provided, explicit, or inherited constructors ([class.ctor])  
> no private or protected non-static data members (Clause [class.access]),  
> no virtual functions, and  
> no virtual, private, or protected base classes ([class.mi]).

For example (sample from the spec draft):

```cpp
struct base1 { int b1, b2 = 42; };
struct base2 {
  base2() {
    b3 = 42;
  }
  int b3;
};

struct derived : base1, base2 {
  int d;
};

derived d1{ {1, 2}, {}, 4};
derived d2{ { }, {}, 4};
```

initializes `d1.b1` with `1`, `d1.b2` with `2`, `d1.b3` with `42`, `d1.d` with `4`, and `d2.b1` with `0`, `d2.b2` with `42`, `d2.b3` with `42`, `d2.d` with `4`.

In our case, it has a more significant impact.

For our overload class, we could implement the following constructor.

```cpp
struct overload : Fs... 
{
  template <class ...Ts>
  overload(Ts&& ...ts) : Fs{std::forward<Ts>(ts)}...
  {} 

  // ...
}
```

But here we have a lot of code to write, and probably it doesn’t cover all of the cases…

With aggregate initialisation, we “directly” call the constructor of lambda from the base class list, so there’s no need to write it and forward arguments to it explicitly.

## Playground


Play with the code [@Coliru](http://coliru.stacked-crooked.com/a/ba1b58473874d45c)

## Summary

The overload pattern is a fascinating thing. It demonstrates several C++ techniques, gathers them together and allows us to write shorter syntax.

In C++14 you could derive from lambdas and build similar helper types, but only with C++17 you can significantly reduce boilerplate code and limit potential errors.

You can read more in the proposal for `overload` [P0051](https://wg21.link/P0051) (not sure if that goes in C++20, but it’s worth to see discussions and concepts behind it).

The pattern presented in this blog post supports only lambdas and there’s no option to handle regular function pointers. In the paper, you can see a much more advanced implementation that tries to handle all cases.

### Your Turn

*   Have you used `std::variant` and visitation mechanism?
*   Have you used `overload` pattern?

### References

*   [Everything You Need to Know About std::variant from C++17](https://www.bfilipek.com/2018/06/variant.html)
*   [How To Use std::visit With Multiple Variants](https://www.bfilipek.com/2018/09/visit-variants.html)
*   [C++ Weekly - Ep 49 - Why Inherit From Lambdas?](https://www.youtube.com/watch?v=3wm5QzdddYc)
*   [C++ Weekly - Ep 48 - C++17’s Variadic `using`](https://www.youtube.com/watch?v=1gNzhE-Tn40)
*   [C++ Weekly - Ep 40 - Inheriting From Lambdas](https://www.youtube.com/watch?v=W-xTpqj31mI)
*   [Overload: Build a Variant Visitor on the Fly - Simplify C++!](https://arne-mertz.de/2018/05/overload-build-a-variant-visitor-on-the-fly/)

## More from the Author

Bartek recently published a book - ["C++17 In Detail"](https://leanpub.com/cpp17indetail?utm_source=devto&utm_campaign=2lines3features) available @Leanpub - rather than reading the papers and C++ specification drafts, you can use this book to learn the new Standard in an efficient and practical way.