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

Boost.Fusion 最後尾に要素を追加するためにjoinを使うのはやめよう

C++

以前、DateTimeライブラリを作ってて嵌ったこと。
Fusion Sequenceの最後尾に要素を追加するために、1要素のvectorを作ってjoinしようとしてました。

#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/include/join.hpp>

#include <iostream>
#include <boost/fusion/include/io.hpp>

namespace fusion = boost::fusion;

template <class Seq, class T>
typename fusion::result_of::join<const Seq, const fusion::vector1<T> >::type
    push(const Seq& seq, const T& x)
{
    return fusion::join(seq, fusion::make_vector(x));
}

int main()
{
    const fusion::vector<int, char> v(3, 'a');

    std::cout << push(v, 3.14) << std::endl;
}
(3 a 2.64195e-308)

はい、データが壊れます。


本来は、fusion::push_backを使えばいいのですが、push_back相当のことをjoinでやろうとすると、右辺がsingle viewではなく単なるvectorになってしまうので、オブジェクトの寿命が尽きてしまっているようです。


remember push_back!

#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/include/push_back.hpp>

#include <iostream>
#include <boost/fusion/include/io.hpp>

namespace fusion = boost::fusion;

template <class Seq, class T>
typename fusion::result_of::push_back<const Seq, T>::type
    push(const Seq& seq, const T& x)
{
    return fusion::push_back(seq, x);
}

int main()
{
    const fusion::vector<int, char> v(3, 'a');

    std::cout << push(v, 3.14) << std::endl;
}
(3 a 3.14)


ちなみに、単なるpush_backの内部実装になりますが、joinでやる場合はsingle_viewを使ってこんな感じで書くことになります。

#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/include/join.hpp>
#include <boost/fusion/include/single_view.hpp>

#include <iostream>
#include <boost/fusion/include/io.hpp>

namespace fusion = boost::fusion;

template <class Seq, class T>
typename fusion::result_of::join<const Seq, const fusion::single_view<T> >::type
    push(const Seq& seq, const T& x)
{
    return fusion::join(seq, fusion::single_view<T>(x));
}

int main()
{
    const fusion::vector<int, char> v(3, 'a');

    std::cout << push(v, 3.14) << std::endl;
}
(3 a 3.14)