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

にゃははー

はへらー

Boost.Fusion 1.58 updates

Boost Boost.Fusion

Boost.Fusion 1.58は頑張ったし、Damien Buhlも頑張ったのでそれなりな更新がいくつかあります。 まだBeta出てない*1けどそろそろmasterがcloseしてbugfixのみになるので機能としてはfixした感じ。

主な新機能

boost::hashのサポート

これまではFusionシーケンスは boost::hash をサポートしていなかったので、Unordered Associative Containerに投げることができませんでした。 今回、新たに hash.hpp が導入され、Boost.UnorderedへFusionシーケンスを投げることが出来るようになりました。 これはForward Sequenceであれば受け付けるので、アダプトしたシーケンスにも使えます。

#include <boost/unordered_set.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/include/equal_to.hpp>
#include <boost/fusion/include/hash.hpp> // new

int main()
{
    boost::unordered_set<boost::fusion::vector<int>> m;
    m.insert(boost::fusion::make_vector(0));
    m.insert(boost::fusion::make_vector(1));
}

今のところ、std::hashは特殊化されていないので、std::unordered_{multi,}{map,set}には直接使えませんが、boost::hashを渡すことで同様のことが出来るようになります。

#include <unordered_set>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/include/equal_to.hpp>
#include <boost/fusion/include/hash.hpp> // new

int main()
{
    std::unordered_set<boost::fusion::vector<int>, boost::hash<boost::fusion::vector<int>>> m;
    m.insert(boost::fusion::make_vector(0));
    m.insert(boost::fusion::make_vector(1));
}

1.59には入れたいと思います。

std::reference_wrapper

boost::reference_wrapperは前々から渡されたら通常の参照に展開するようになっていたんだけど、今回std::reference_wrapperもそうなるようになった。

#include <functional>
#include <cassert>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/include/at_c.hpp>

int main()
{
    int i = 0;
    auto v = boost::fusion::make_vector(std::ref(i));
    boost::fusion::at_c<0>(v) = 1;
}

reference_wrapperのままでもええやんって思うかもだけど、reference_wrapperのまま格納されると上のコードはコンパイルできない。

[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

std::tuple

std::tupleのサポートは実は前々から存在してはいたんだけど、ドキュメントが無かったり、一分実装が抜けていたりした。 今回ドキュメントを用意したし、大体実装されているはず。

std::tuple - develop

いくつかのresult_ofをSFINAE-friendlyに

いくつかというのがミソ。1.59には全部をSFINAE-friendlyにしたい

アダプタでの暗黙的な型推論をサポート

これまでは構造体をアダプトするには型を書かないといけませんでした。

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/at_c.hpp>

namespace foo
{
    namespace very_very_cool_namespace
    {
        typedef int how_quite_greatest_awesome_type;
    }

    struct bar
    {
        very_very_cool_namespace::how_quite_greatest_awesome_type hoge;
        very_very_cool_namespace::how_quite_greatest_awesome_type fuga;
    };
}

BOOST_FUSION_ADAPT_STRUCT(
    foo::bar,
    (foo::very_very_cool_namespace::how_quite_greatest_awesome_type, hoge)
    (foo::very_very_cool_namespace::how_quite_greatest_awesome_type, fuga)
)

int main()
{
    foo::bar x = { 0 };
    boost::fusion::at_c<0>(x) = 0xdeadbeef;
}

very_very_cool_namespace::how_quite_greatest_awesome_typeを書くのは非常にだるいですし、構造体の変更に対して柔軟に対応できません。 一応これまでであっても型名の代わりにBOOST_FUSION_ADAPT_AUTOを使えばBoost.TypeOfでの推論を使用できていましたが、依然として書かないといけないのは面倒です。

今回、Damienが頑張ってプリプロセッサしたところ、Variadic Macrosをサポートした環境では更に省略出来るようになりました。

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/at_c.hpp>

namespace foo
{
    namespace very_very_cool_namespace
    {
        typedef int how_quite_greatest_awesome_type;
    }

    struct bar
    {
        very_very_cool_namespace::how_quite_greatest_awesome_type hoge;
        very_very_cool_namespace::how_quite_greatest_awesome_type fuga;
    };
}

BOOST_FUSION_ADAPT_STRUCT(
    foo::bar,
    hoge,
    fuga
)

int main()
{
    foo::bar x = { 0 };
    boost::fusion::at_c<0>(x) = 0xdeadbeef;
}

C++11/14 constexprのサポート

#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/include/at_c.hpp>

int main()
{
    constexpr auto v = boost::fusion::make_vector("foo", 0xdeadbeef);
    static_assert(boost::fusion::at_c<1>(v) == 0xdeadbeef, "Sadly, beef is daed ...");
}

見たまんまですね。これで不幸にも実行ができなくなってしまった環境であってもコンパイル時に計算できるので安心ですね。

C++14なら基本的にconstexprになってるはずです。C++11だといくつかがまだ対応出来てないです。少しずつなんとかしたいですね。

*1:3/11予定