Boost logo

Boost Users :

Subject: Re: [Boost-users] [Proto] First steps
From: Eric Niebler (eric_at_[hidden])
Date: 2010-11-09 15:30:56


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

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net