[move] differences between results in C++03 and C++11 modes
Hi! Some time ago I encountered a problem with assigning the return value of boost::move() to a non-const reference in C++11 mode, but not in C++03 mode. See [1] for a StackOverflow question that I created for this issue. It contains all the details so for brevity I won't repeat them here. Could anyone explain this issue? Is this a limitation of C++03 emulation or a defect in the implementation? Best regards, Adam Romanek [1] http://stackoverflow.com/questions/21138869/why-does-assigning-the-return-va...
El 11/02/2014 8:55, Adam Romanek escribió:
Hi!
Some time ago I encountered a problem with assigning the return value of boost::move() to a non-const reference in C++11 mode, but not in C++03 mode. See [1] for a StackOverflow question that I created for this issue. It contains all the details so for brevity I won't repeat them here. Could anyone explain this issue? Is this a limitation of C++03 emulation or a defect in the implementation?
Yes, it's a limitation of boost move. When called with the emulation code boost::move() returns a type rv<T> & that is convertible to T (and that is the key point to implement emulated move semantics). However in C++11 you return a T&& (unnamed rvalue reference) which is not assignable to T &. In your case, as R is std::ostream &, the emulation return rv<std::ostrean> (convertible to std::ostream &) and the C++11 version returns std::ostream &&, which is not convertible to std::ostream &. I guess we could add a new macro to boost move for return types. In emulated mode, it moves the return value, In C++11 mode it only return the value (If RVO can't be applied the compiler will do an implicit move). Something like: //return boost::move(r) in emulation //return r in C++11 return BOOST_MOVE_RET(r); If you think it's a good idea, please fill a ticket. Best, Ion
2014-02-11 14:11 GMT+01:00 Ion Gaztañaga <igaztanaga@gmail.com>:
El 11/02/2014 8:55, Adam Romanek escribió:
Hi!
Some time ago I encountered a problem with assigning the return value of boost::move() to a non-const reference in C++11 mode, but not in C++03 mode. See [1] for a StackOverflow question that I created for this issue. It contains all the details so for brevity I won't repeat them here. Could anyone explain this issue? Is this a limitation of C++03 emulation or a defect in the implementation?
Yes, it's a limitation of boost move. When called with the emulation code boost::move() returns a type rv<T> & that is convertible to T (and that is the key point to implement emulated move semantics). However in C++11 you return a T&& (unnamed rvalue reference) which is not assignable to T &.
In your case, as R is std::ostream &, the emulation return rv<std::ostrean> (convertible to std::ostream &) and the C++11 version returns std::ostream &&, which is not convertible to std::ostream &.
I guess we could add a new macro to boost move for return types. In emulated mode, it moves the return value, In C++11 mode it only return the value (If RVO can't be applied the compiler will do an implicit move). Something like:
//return boost::move(r) in emulation //return r in C++11 return BOOST_MOVE_RET(r);
+1 I've written and use such a macro myself. Regards, Kris
On Tue, Feb 11, 2014 at 9:14 AM, Krzysztof Czainski <1czajnik@gmail.com>wrote:
2014-02-11 14:11 GMT+01:00 Ion Gaztañaga <igaztanaga@gmail.com>:
El 11/02/2014 8:55, Adam Romanek escribió:
Hi!
Some time ago I encountered a problem with assigning the return value of boost::move() to a non-const reference in C++11 mode, but not in C++03 mode. See [1] for a StackOverflow question that I created for this issue. It contains all the details so for brevity I won't repeat them here. Could anyone explain this issue? Is this a limitation of C++03 emulation or a defect in the implementation?
Yes, it's a limitation of boost move. When called with the emulation code boost::move() returns a type rv<T> & that is convertible to T (and that is the key point to implement emulated move semantics). However in C++11 you return a T&& (unnamed rvalue reference) which is not assignable to T &.
In your case, as R is std::ostream &, the emulation return rv<std::ostrean> (convertible to std::ostream &) and the C++11 version returns std::ostream &&, which is not convertible to std::ostream &.
I guess we could add a new macro to boost move for return types. In emulated mode, it moves the return value, In C++11 mode it only return the value (If RVO can't be applied the compiler will do an implicit move). Something like:
//return boost::move(r) in emulation //return r in C++11 return BOOST_MOVE_RET(r);
+1 I've written and use such a macro myself. Regards, Kris
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
I recently wanted to write such a macro too. Objects marked with BOOST_MOVABLE_BUT_NOT_COPYABLE have to be returned with "return boost::move(temp)" or C++03 compilers try to use the private copy-constructor on temp. Doing a boost::move return prevents NRVO in C++03, and C++11 (according to the language purists and gcc 4.7.3). This macro would at least provide NRVO capabilities in C++11. I think C++03 support for NRVO in this situation is foolish; boost::move would have to invoke a private copy-constructor on the user type and hope the compiler didn't generate a function call to it. The documentation doesn't list these limitations AFAIK. Lee
El 12/02/2014 2:34, Lee Clagett escribió:
I recently wanted to write such a macro too. Objects marked with BOOST_MOVABLE_BUT_NOT_COPYABLE have to be returned with "return boost::move(temp)" or C++03 compilers try to use the private copy-constructor on temp. Doing a boost::move return prevents NRVO in C++03, and C++11 (according to the language purists and gcc 4.7.3). This macro would at least provide NRVO capabilities in C++11. I think C++03 support for NRVO in this situation is foolish; boost::move would have to invoke a private copy-constructor on the user type and hope the compiler didn't generate a function call to it. The documentation doesn't list these limitations AFAIK.
I've committed a first implementation to the develop branch: SHA-1: 062000ed68cecf59f29b99f5a6167529ea359979 * Added BOOST_MOVE_RET [develop 062000e] Added BOOST_MOVE_RET 7 files changed, 496 insertions(+), 129 deletions(-) create mode 100644 example/doc_move_return.cpp create mode 100644 proj/vc7ide/doc_move_return.vcproj Documentation is updated with the details. I also discovered that Visual 2010 and 2012 are non-conforming when returning movable-only values. I'm sure this first version will have several bugs, but let me know if this is a good starting point. Best, Ion
Le 11/02/14 14:11, Ion Gaztañaga a écrit :
El 11/02/2014 8:55, Adam Romanek escribió:
Hi!
Some time ago I encountered a problem with assigning the return value of boost::move() to a non-const reference in C++11 mode, but not in C++03 mode. See [1] for a StackOverflow question that I created for this issue. It contains all the details so for brevity I won't repeat them here. Could anyone explain this issue? Is this a limitation of C++03 emulation or a defect in the implementation?
Hi, if I understand your function definition is not correct in C++11 |template <class R, class F> R call_under_lock(F f) { // lock(); R r= f(); // unlock(); return boost::move(r); }| Would the following work for you in C++11? |template <class R, class F> R call_under_lock(F f) { locker lk(...); return f(); }| If R is movable only, wouldn't the previous code work with the Boost.Move emulation? If you want to write your code using an intermediary variable shouldn't you need an indirection, let me call it move_if_no_reference |template <class R, class F> R call_under_lock(F f) { // lock(); R r= f(); // unlock(); return boost::move_if_no_reference<R>()(r); }| template <class T> struct move_if_no_reference { T&& operator (T& v) noexcept { return std::move(v);} }; template <class T> struct move_if_no_reference<T&> { T& operator (T& v) noexcept {return v;}; }; ||
Yes, it's a limitation of boost move. When called with the emulation code boost::move() returns a type rv<T> & that is convertible to T (and that is the key point to implement emulated move semantics). However in C++11 you return a T&& (unnamed rvalue reference) which is not assignable to T &.
In your case, as R is std::ostream &, the emulation return rv<std::ostrean> (convertible to std::ostream &) and the C++11 version returns std::ostream &&, which is not convertible to std::ostream &.
I guess we could add a new macro to boost move for return types. In emulated mode, it moves the return value, In C++11 mode it only return the value (If RVO can't be applied the compiler will do an implicit move). Something like:
//return boost::move(r) in emulation //return r in C++11 return BOOST_MOVE_RET(r);
What am I missing? Why you don't need to call std::move in the C++11 case? I don't think this works as the PO wants a move if the return type is not a non const reference. Best, Vicente
participants (5)
-
Adam Romanek
-
Ion Gaztañaga
-
Krzysztof Czainski
-
Lee Clagett
-
Vicente J. Botet Escriba