読者です 読者をやめる 読者になる 読者になる

C++でパターンマッチ

C++

Boost.Variantについて調べていたらすごいものを見つけてしまった。

http://archives.free.net.ph/message/20090406.185710.d34aa406.el.html


こういうvariantがあったときに

variant< 
    int 
  , pair<int,double> 
  , pair<int,int> 
  , pair<double,int> 
> var;

Visitorを書かないといけないのはめんどくさい。
そこで、Vairantにどんな型が格納されているかパターンマッチしてしまえ、というライブラリの提案がかなり前にあったようです。

switch_(var) 
  |= case_< pair<_1,_1> >(...) // matches pair<int,int> 
  |= case_< pair<int,_> >(...) // matches pair<int,*> 
  |= case_< pair<_,_> >(...) // matches pair<*,*> 
  |= case_< int >(...) 
;

Sandboxにあるコードが古くて、Boost 1.43.0で動かすのに苦戦しましたが、こんな感じで使えました。

#include <iostream>
#include <utility>
#include <boost/variant.hpp>
#include <boost/type_switch.hpp>
#include <boost/mpl/arg.hpp>

using namespace boost::type_switch;
using std::pair;
using namespace boost::mpl::placeholders;

struct same_pair {
    template <class T, class U>
    void operator()(const std::pair<T, U>& x) const
    {
        std::cout << "same pair" << std::endl;
    }
};

struct first_int {
    template <class T, class U>
    void operator()(const std::pair<T, U>& x) const
    {
        std::cout << "first int" << std::endl;
    }
};

struct int_func {
    void operator()(int x) const
    {
        std::cout << "int_func" << std::endl;
    }
};

struct default_func {
    template <class T>
    void operator()(const T& x) const
    {
        std::cout << "default_func" << std::endl;
    }
};

typedef
    boost::variant<
        int,
        pair<int, double>,
        pair<int, int>,
        pair<double, int>
    >
type;

void f(type var)
{
    switch_(var)
        |= case_< pair<_1, _1> >(same_pair())   // pair<int, int>にマッチ
        |= case_< pair<int, _> >(first_int())   // pair<int, *>にマッチ
        |= case_< int >(int_func())             // intにマッチ
        |= default_(default_func())             // その他
    ;
}

int main()
{
    f(std::make_pair<int, int>(1, 2));          // same_pair
    f(std::make_pair<int, double>(1, 3.14));    // same_pair...ん?
    f(3);                                       // int_func
}

使い方間違ってるのかもしれない。
しかし、これには夢がある。