[move] explicit moving from a rvalue

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()() { } };

El 26/03/2012 21:42, Vicente J. Botet Escriba escribió:
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);
Why is the constructor explicit? Ion

El 26/03/2012 22:15, Ion Gaztañaga escribió:
El 26/03/2012 21:42, Vicente J. Botet Escriba escribió:
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);
Why is the constructor explicit?
Sorry, I replied too fast, thinking it was a plain move constructor. I see the need for it.
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.
I just wonder if some kind of "always_inline" attribute for this proposal would fix the performance issue. Ion

Le 26/03/12 22:18, Ion Gaztañaga a écrit :
El 26/03/2012 22:15, Ion Gaztañaga escribió:
El 26/03/2012 21:42, Vicente J. Botet Escriba escribió:
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);
Why is the constructor explicit?
Sorry, I replied too fast, thinking it was a plain move constructor. I see the need for it.
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.
I just wonder if some kind of "always_inline" attribute for this proposal would fix the performance issue.
IIRC, the approach was based on type erasure, so I don't think that inlining will help. Jerry? Vicente

On Mon, Mar 26, 2012 at 1:41 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Le 26/03/12 22:18, Ion Gaztañaga a écrit :
El 26/03/2012 22:15, Ion Gaztañaga escribió:
El 26/03/2012 21:42, Vicente J. Botet Escriba escribió:
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);
Why is the constructor explicit?
Sorry, I replied too fast, thinking it was a plain move constructor. I see the need for it.
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.
I just wonder if some kind of "always_inline" attribute for this proposal would fix the performance issue.
IIRC, the approach was based on type erasure, so I don't think that inlining will help. Jerry?
[I assume that's me.] Perhaps. I can look into it once I get back from vacation. Ping me if you don't hear anything about it in a couple weeks :) - Jeff

On Mon, Mar 26, 2012 at 12:42 PM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
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.
Agreed, although I would think a sufficiently advanced and aggressive compiler could optimize the type erasure away. 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.
I played around with such a macro (essentially wrapping the argument in an explicit cast if it was an rvalue of move-emulation-enabled type), but haven't used it extensively. Hiding everything behind the macro implementation, I think, is preferable to adding to the move emulation interface. In any case, I question whether use of such a macro will catch on. It's...ugly :/
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<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?
The macro sounds plausible to me; I'm not convinced of the need for the move member function. Best,
Vicente
/////////////////////////////
[...] - Jeff
participants (3)
-
Ion Gaztañaga
-
Jeffrey Lee Hellrung, Jr.
-
Vicente J. Botet Escriba