Boost logo

Boost :

Subject: [boost] [move] explicit moving from a rvalue
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2012-03-26 15:42:50


Hi Ion,

With the current emulation of move semantics of Boost.Thread using
Boost.move, I have a case that I would like to make working in a
portable way

   boost::thread t = boost::thread( MoveOnly());

The library declares the template move constructor from a movable
callable as as follows

         template <class F>
         explicit thread(boost::rv<F>& f);

and MoveOnly is declared as defined below.

The problem is a know limitation as the compiler is unable to deduce F
as been MoveOnly even if MoveOnly is convertible to boost::rv<MoveOnly>&
Jeffrey Lee Hellrung, Jr. made a proposal to try to solve the issue, but
his proposal has a performance penality.

Here it is a less elegant but efficient enough alternative. The addition
of a explicit move conversion as

   ::boost::rv<MoveOnly>& move()
   {
     return *static_cast< ::boost::rv<MoveOnly>* >(this);
   }

allows to the following to work as expected

   boost::thread t = boost::thread( MoveOnly().move());

While this workaround works when we are using the emulation it doesn't
works when rvalue references are supported.

I have defined a macro BOOST_EXPLICIT_MOVE that allows to write portable
code

#if ! defined BOOST_NO_RVALUE_REFERENCES
#define BOOST_MOVE(RVALUE) RVALUE
#else
#define BOOST_MOVE(RVALUE) RVALUE.move()
#endif

that can be used as

   boost::thread t = boost::thread( BOOST_MOVE(MoveOnly()));

The move() function is not really needed as the macro can hide the
needed conversion, but could be preferred by users that don't need to
make portable programs.

The evident liability is of course the use of the macro. Is there
something wrong on this design, something to to improve?

The same design can be used on compilers, such as as SunStudio (see
https://svn.boost.org/trac/boost/ticket/6222), that prefer the overload
of a private copy constructor to an public move constructor. On these
kind of compilers the following overload

   private:
     MoveOnly(MoveOnly&);
   public
     MoveOnly(boost::rv<MoveOnly>&)

makes the following to fail at compile time

MoveOnly MakeMoveOnly() {
   return MoveOnly();
}

but

MoveOnly( MakeMoveOnly(() {
   return BOOST_MOVE(MoveOnly());
}

will work.

Do you think that member functions as the explicit move() and a macro as
BOOST_MOVE can be added to Boost.Move emulation?

Best,
Vicente

/////////////////////////////

class MoveOnly
{
#ifndef BOOST_NO_DELETED_FUNCTIONS
   public:
   MoveOnly(const MoveOnly&)=delete;
   MoveOnly& operator=(MoveOnly const&);
#else
   private:
   MoveOnly(MoveOnly&);
   MoveOnly& operator=(MoveOnly&);
   public:
#endif
   MoveOnly()
   {
   }
#ifndef BOOST_NO_RVALUE_REFERENCES
   MoveOnly(MoveOnly&&)
   {}
#else
#if defined BOOST_THREAD_USES_MOVE
   MoveOnly(boost::rv<MoveOnly>&)
   {}
   MoveOnly& operator=(boost::rv<MoveOnly>&)
   {
     return *this;
   }
   operator ::boost::rv<MoveOnly>&()
   {
     return *static_cast< ::boost::rv<MoveOnly>* >(this);
   }
   operator const ::boost::rv<MoveOnly>&() const
   {
     return *static_cast<const ::boost::rv<MoveOnly>* >(this);
   }
   ::boost::rv<MoveOnly>& move()
   {
     return *static_cast< ::boost::rv<MoveOnly>* >(this);
   }
   const ::boost::rv<MoveOnly>& move() const
   {
     return *static_cast<const ::boost::rv<MoveOnly>* >(this);
   }
#else
#error
#endif
#endif

   void operator()()
   {
   }
};


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk