ユーザー定義のクラスをFusionのコンテナ(タプル)として使用する

Boost.Fusionでは、様々なデータ構造のタプルが提供され、
それらのタプルに対して使用できるSTLライクなアルゴリズムも提供されています。
たとえば、タプルの全要素を出力するには以下のように書きます。

#include <iostream>
#include <string>
#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/algorithm.hpp>

struct disper {
    // パラメータの型が毎回変わる(int, double, std::string)のでテンプレートにする
    template <class T>
    void operator()(const T& x) const
    {
        std::cout << x << std::endl;
    }
};

int main()
{
    using namespace boost::fusion;

    vector<int, double, std::string> p(24, 3.14, "Akira");
    for_each(p, disper());
}
24
3.14
Akira


これだけでもかなり便利ですが、Boost.Fusionでは、ユーザー定義のクラスに対して
Fusionのアルゴリズムを適用する手段も提供してくれています。


たとえば、以下のpersonクラスの場合には

struct person {
    int id;
    int age;
    std::string name;

    person(int id, int age, const std::string& name)
        : id(id), age(age), name(name) {}
};

以下のようなマクロを書きます。

#include <boost/fusion/adapted/struct/adapt_struct.hpp>

BOOST_FUSION_ADAPT_STRUCT (
    person,
    (int, id)
    (int, age)
    (std::string, name)
)

これだけで、personクラスをBoost.Fusionのコンテナとして使用できます。

person p(1, 24, "Akira");
boost::fusion::for_each(p, disper());
1
24
Akira

Boost.Fusionのiterator_facadeとsequence_facadeも試してみましたが
そっちだとどうしてもコード量がかなり多くなってしまうのが、
この方法だとマクロ一発流すだけなのでとてもお手軽です。
ちなみに、BOOST_FUSION_ADAPT_STRUCTでアダプトされた型はランダムアクセスシーケンスになります。



以下、全ソース

#include <iostream>
#include <string>
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>

struct person {
    int id;
    int age;
    std::string name;

    person(int id, int age, const std::string& name)
        : id(id), age(age), name(name) {}
};

BOOST_FUSION_ADAPT_STRUCT (
    person,
    (int, id)
    (int, age)
    (std::string, name)
)

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

int main()
{
    person p(1, 24, "Akira");
    boost::fusion::for_each(p, disper());
}


【参照】

BOOST_FUSION_ADAPT_STRUCT - Boost C++ Libraries