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