The other problem besides move semantics that rvalue references were designed
to solve is the perfect forwarding problem. Consider the following simple
factory function:
template<typename T, typename Arg> shared_ptr<T> factory(Arg arg) { return shared_ptr<T>(new T(arg)); }Obviously, the intent here is to forward the argument arg from
the factory function to T 's constructor. Ideally, as far as
arg is concerned, everything should behave just as if the
factory function weren't there and the constructor were called directly in
the client code: perfect forwarding. The code above fails miserably at that:
it introduces an extra call by value, which is particularly bad if the constructor
takes its argument by reference.
The most common solution, chosen e.g. by template<typename T, typename Arg> shared_ptr<T> factory(Arg& arg) { return shared_ptr<T>(new T(arg)); }That's better, but not perfect. The problem is that now, the factory function cannot be called on rvalues: factory<X>(hoo()); // error if hoo returns by value factory<X>(41); // errorThis can be fixed by providing an overload which takes its argument by const reference: template<typename T, typename Arg> shared_ptr<T> factory(Arg const & arg) { return shared_ptr<T>(new T(arg)); }There are two problems with this approach. Firstly, if factory had not one,
but several arguments, you would have to provide overloads for all combinations of
non-const and const reference for the various arguments. Thus, the solution scales
extremely poorly to functions with several arguments.
Secondly, this kind of forwarding is less than perfect because it blocks out
move semantics: the argument of the constructor of |