✡️

C++ overload pattern - オーバーロードパターン

2023/11/29に公開

オーバーロードパターン

2 Lines Of Code and 3 C++17 Features - The overload Patternという記事を見つけて,初めてオーバーロードパターンという言葉を耳にしました.
気になったので調べてみると,stack overflowにあった質問では,良く知られたパターンとあります.

しかし,日本語で検索してみても通常のオーバーロードが引っ掛かるばかりで日本語での記事は無さそうだったのでまとめてみました.もし日本語では別の名前で普及しているよ,という話があれば教えていただけると幸いです.

簡単に言うと,複数のlambdaをオーバーロードとしてまとめるためのパターンのようです.

template <class... Ts> struct overload : Ts... { using Ts::operator()...; }
// C++17では次の型推論のガイドが必要
template <class... Ts> overload(Ts...) -> overload<Ts...>;

これは次のように使います.

#include <iostream>

using namespace std;

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

int main()
{
    auto print = overload {
        [](int)    { cout << "int" << endl; },
        [](double) { cout << "double" << endl; }
    };
    print(1);
    print(1.0);
}

Compiler Explorerへのリンク

lambdaがoperator()を実装したクラスを生成するので,それを継承したクラスでそのoperator()を使えるようにしてオーバーロードとしてまとめる,というパターンのようです.

これを何に使うのかというと,型安全でunionの代わりになるように作られたstd::variantと,そのvariantが保持している値にアクセスするstd::visitを使う際によく使われるようです.

#include <iostream>
#include <variant>

using namespace std;

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

int main()
{
    using value_t = std::variant<int, double>;

    value_t v1 = 1;
    value_t v2 = 2.0;

    auto print = overload {
        [](int)    { cout << "int" << endl; },
        [](double) { cout << "double" << endl; }
    };
    visit(print, v1);
    visit(print, v2);
}

Compiler Explorerへのリンク

std::variantを使う機会が無かったのですが,なかなか面白そうなので,職場で使えそうな部分が無いかなって探してしまいそうです.

参考資料

Discussion