C++でパターンマッチ


背景

Blawnの開発でASTなどの直和型っぽいものを扱う際にstd::variantを使っているのですが、関数型言語的なパターンマッチができないのがとても不便だったので頑張ってそれっぽいものを作ってみました。ソースはgithubにおいてあります。

実装の方針

Match(variant)
{
    case int: {/*any processing*/}
}

みたいな感じの見た目にしたかったのでMatchクラスのコンストラクタでvariantを、operator()のオーバーロードでパターンと処理(関数)をそれぞれ受け取ることにしました。

ということで最終的には

#include <iostream>
#include <optional>
#include <variant>
#include <string>
#include "pattern_match.hpp"


int main()
{
    auto variant = std::variant<int, std::string, double, float>(10);
    std::string input;
    std::cout << "please input text: ";
    std::cin >> input;
    variant = input;

    auto result = satch::Match{variant}(
        satch::Type<std::string>(), [](auto&& str) 
            {
                std::cout << "variant contains string value: " << str << std::endl;
                return 1; 
            },
        satch::Value<int>(10), [](auto&& value)
            {
                std::cout << "variant contains int value 10" << val << std::endl;
                return 2;
            },
        satch::Default(),[](auto&& variant) 
            {
                std::cout << "variant.index() = " << variant.index() << std::endl;
                return 3;
            }
        );

    std::cout << "matching returned: " << result << std::endl;

    return 0;
}
$ g++ -std=c++17 example.cpp; ./a.out
please input text: abc
variant contains string value: abc
matching returned: 1

こういう見た目になりました。
operator()の引数が「Pattern,Function,Pattern,Function...」の順に並んでいることを前提にして処理を行なっています。