This question is mixing two different concepts together.
An rvalue-reference is usually used to indicate that the constructor or function will destructively mutate that object (such as moving the contents out, or removing internal data), which is part of idiomatic move-semantics. Like lvalue-references, this also works with conversions-to-base types (so a Derived&&
can be passed to a Base&&
). Since the argument is a specific type, it's tightly constrained only to types that are either exactly, or convertible-to, that reference.
Forwarding references, on the other hand, allow for forwarding any (possibly constrained) template-deduced-type and matches the reference type exactly. Using forwarding references has several considerations:
Forwarding references can only be used with template
s, since the type must be deduced. It is not always desirable to throw everything in template, since each different type will be a unique instantiation, and this may also relocate code from a source-file into a header-file (which can affect compilation times).
Forwarding references are often unambiguously better matches than equivalent overloads. If you have the following:
void do_something(const Foo&);
template <typename T&&>
void do_something(T&&);
...
auto f = Foo{};
do_something(f);
Then this will call do_something(T&&)
and not do_something(const Foo&)
because f
is an lvalue reference of Foo
, so the template is an unambiguously better match.
How often do you really need any T
type? This is often more-so in generic code to forward argument/data (hence being called forwarding references). In most user-code, forwarding references are not generally necessary.
It makes more sense for a Person
to be constructible from a string
name, rather than allowing a user to pass something like a vector<int>::iterator
There are no semantics associated with forwarding references, since it matches anything.
As a template, you push any errors to instantiation time. If a user passes the wrong input to the forwarding-reference that is not properly constriained, you may get pages of template errors.
Fundamentally, they satisfy different things.
With that out of the way: rvalue-references could be considered beneficial since they are:
- idiomatic
- simple (KISS principle)
- lightweight (one level of indirection, no additional instantiations that templates would have)
- self-documenting (A
Foo&&
clearly requires a Foo
instance; T&&
accepts anything)
Ultimately which of the two is better depends on the job that needs to be done.
See Also: