にゃははー

はへらー

Boost.Phoenix V3でのmove

例えば common.hpp を次のように書いたとする。

#include <boost/move/move.hpp>
struct S
{
    BOOST_MOVABLE_BUT_NOT_COPYABLE(S)

public:
    S() {}
    S(BOOST_RV_REF(S)) {}
};

void f(S) {}

で、このSをfにmoveしてみる。

#include "common.hpp"

#include <boost/move/move.hpp>

int main()
{
    S s;
    f(boost::move(s));
}

まぁここまでは当然動く。

で、ここから本題。上のコードをBoost.Phoenix化したくて下のように書いてみても当然エラーになる。

#include "common.hpp"

#include <boost/phoenix/core.hpp>
#include <boost/phoenix/bind.hpp>

int main()
{
    S s;
    boost::phoenix::bind(f, boost::move(s))();
}

まぁこれは何となく分かるわけで、例えばreference_wrapperみたいに

#include "common.hpp"

#include <boost/phoenix/core.hpp>
#include <boost/phoenix/bind.hpp>

#include <boost/ref.hpp>

template <typename T>
struct rvref
{
    rvref(T &value)
      : value(&value) {}

    operator BOOST_RV_REF(T)() const { return boost::move(*value); }
public:
    T *value;
};

int main()
{
    S s;
    rvref<S> rvs(s);
    boost::phoenix::bind(f, boost::ref(rvs))();
}

って適当に書いてもよくわからないがC++11でしか通らない。

C++11だけで通っても結局は


なわけで、、、、

まぁMotivationとしては同じコードで03/11で動いて欲しいと。ライブラリコードだとそうなりますね。まぁBOOST_NO_LAMBDASでdispatchしてもいいですけど。

どちらにせよmoveっぽい何かは欲しいわけで、仕方ないから書いた。
https://github.com/Flast/boost.mmm/blob/master/boost/mmm/detail/phoenix/move.hpp

そうするとこうなるわけで、

#include "common.hpp"

#include <boost/phoenix/core.hpp>
#include <boost/phoenix/bind.hpp>
#include <boost/mmm/detail/phoenix/move.hpp>

#include <boost/ref.hpp>

int main()
{
    S s;
    boost::phoenix::bind(f, boost::mmm::detail::phoenix::move(boost::ref(s)))();
}

結局BOOST_NO_RVALUE_REFERENCEで分岐するぐらいだったらlambdaで分岐しても良かったかもしれないと今更ながら思ってる。
とはいえrv-refあってもlambdaないclang 3.0とかあるわけで、結局必要か。