Let's say we have a class that embed another parametric one, that has to support both copy and move. And let's assume that -in certain circumstance- there is the need to get out the inner value somehow.
A typical approach can be this one:
template<class T>
class wrapper
{
public:
wrapper() :val() {}
wrapper(T s) :val(std::move(s)) {}
wrapper(const wrapper& s) :val(s.val) {}
wrapper(wrapper&& s) :val(std::move(s.val)) {}
wrapper& operator=(wrapper s) { val = std::move(s.val); return *this; }
T value() const { return val; }
private:
T val;
};
That's not the only way of doing it, and may be there is no need to expliciate copy and move, but let them be.
The point is another: Suppose T -in ceratin instances- is itself a copy/movable class.
Of course, wrapper::value() returns a copy of T.
Now suppose the returned T has to go as a parameter into another call, and that the containing wrapper is temporary.
The simpler simulation is
calledfn(wrapper<T>(someT).value());
Again: done in this way is clueless, but more complex cases require this trivial one to work.
In theory we can admit to move away val from its temporary wrapper to give it to the caller, but...
what signature should have the value() method so that it is bound when wrapper<T> is temporary but is not bound when it is not temporary, for which value() const should be preferred?
In C++11 you can overload methods on wether or not the this-pointer is a rvalue:
T value() &&; //Will only be called if the object is a mutable rvalue
T value() const &; //Will only be called if the object is an lvalue
Note that according to 13.1.2 [over.load]in the standard if any overload has a reference specifier (lvalue or rvalue) all have to get one. So The overload for the non-temporary case has to be const &. I'm not completely sure wether or not this will bind to a const r-value, so you might need a const && overload to catch that case.
I don't know about the compiler support for this feature, so this might be somewhat theoretical if the support isn't there yet. In that case you might work around by creating a move_value method and using a free function which dispatches to the correct method:
template<class T> class wrapper {
...
T value() const;
T move_value();
};
template<typename T> T value(wrapper<T>&& self) { return std::move(self.move_value(); }
template<typename T> T value(const wrapper<T>& self) { return std::move(self.value(); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With