
On 11/9/2010 11:27 AM, Eric Niebler wrote:
Any idea?
As you have learned, Proto is not move-aware. My hand-wavy solution would be to (a) be sure that everything is held by value in an ET. With 1.42, that's by using proto::by_value_generator. In 1.44, the preferred solution is with a domain-specific as_child implementation. And (b) to wrap move-only types in a "copyable" type that, in its copy ctor, moves the wrapped value.
I'll see if I can come up with an example that demonstrates.
Here is a Proto algorithm that deep-copies a tree that contains a move-only object. This doesn't directly answer your question, but might get you moving in the right direction. (Tested on VC10.) #include <boost/proto/proto.hpp> #include <typeinfo> #include <string> #include <iostream> namespace proto=boost::proto; namespace mpl=boost::mpl; using proto::_; // A move-only type struct move_only { move_only() : what_("valid") {} move_only(move_only && that) : what_("valid") { that.what_ = "moved from"; } ~move_only() { what_ = "deleted"; } char const *what_; private: move_only(move_only const &); move_only& operator=(move_only const &); }; // A wrapper for move-only types that moves on copy template<typename T> struct move_on_copy { explicit move_on_copy(T && t) : t_(std::move(t)) {} move_on_copy(move_on_copy const & that) : t_(std::move(that.t_)) {} private: move_on_copy &operator=(move_on_copy const &); mutable T t_; }; // A callable that wraps a move-only type in move_on_copy struct _move : proto::callable { template<typename Sig> struct result; template<typename This, typename T> struct result<This(T)> { typedef move_on_copy<typename boost::remove_reference<T>::type> type; }; template<typename T> move_on_copy<typename boost::remove_reference<T>::type> operator()(T && t) const { return move_on_copy<typename boost::remove_reference<T>::type>(std::move(t)); } }; // A type-trait we can use to detect move-only types template<typename T> struct is_move_only : mpl::false_ {}; template<typename T> struct is_move_only<T &> : is_move_only<T> {}; template<typename T> struct is_move_only<T const> : is_move_only<T> {}; template<> struct is_move_only<move_only> : mpl::true_ {}; // A pattern that matches move-only terminals struct MoveOnlyTerminal : proto::and_< proto::terminal<_> , proto::if_<is_move_only<proto::_value>()> > {}; // An algorithm that deep-copies a Proto expression tree, wrapping // move-only types in move_on_copy struct DeepCopy : proto::or_< proto::when<MoveOnlyTerminal, proto::_make_terminal(_move(proto::_value))> , proto::when<proto::terminal<proto::_>, proto::_make_terminal(proto::_byval(proto::_value))> , proto::nary_expr<proto::_, proto::vararg<DeepCopy> > > {}; int main() { move_only a; move_only b(std::move(a)); move_on_copy<move_only> e(std::move(b)); move_on_copy<move_only> f(e); // move! proto::terminal<move_only>::type y = {std::move(b)}; // This deep-copies the tree, wrapping all move-only types // in move_on_copy. DeepCopy()(1 + y + 42); } HTH, -- Eric Niebler BoostPro Computing http://www.boostpro.com