I want to make a function that takes an optional reference to an object, and creates one for the duration of the function if it is not provided, i.e.
void Foo(Bar& b = Bar()) { /* stuff */ }
This is, of course, invalid code, as a Bar
cannot be implicitly converted to a Bar
reference in this context. The reference can't be const
, as b
is mutated inside the function.
You can get around this by using an rvalue reference, i.e.
void Foo(Bar&& b = Bar()) { /* stuff */ }
Is this a valid use of rvalue references? Callers now have to call std::move
on their Bar
arguments, even though I have no intention of clearing the passed Bar
, as is usually the case when you are passing rvalues.
rvalue references are more often used as function parameters. This is most useful for function overloads when you want to have different behavior for lvalue and rvalue arguments. Rule 1: Do not write && to return type of a function, and there is no need to return a local variable using std::move .
Rvalue references is a small technical extension to the C++ language. Rvalue references allow programmers to avoid logically unnecessary copying and to provide perfect forwarding functions. They are primarily meant to aid in the design of higer performance and more robust libraries.
If the function argument is an rvalue, the compiler deduces the argument to be an rvalue reference. For example, assume you pass an rvalue reference to an object of type X to a template function that takes type T&& as its parameter. Template argument deduction deduces T to be X , so the parameter has type X&& .
An lvalue reference can bind to an lvalue, but not to an rvalue.
So you have a function that takes an in-out parameter that it is going to modify to pass back information to the caller.
But you want the parameter to be optional.
So your solution is to make the parameter appear to be an in parameter, by requiring callers to move arguments (which would usually mean they lost whatever state they had or may be in an unspecified state). That is a bad, bad design. You will confuse callers with a weird API created for the convenience of the function's internal implementation. You should design APIs for the users, not the implementors.
You can either do what Deduplicator suggests and split it into two functions, one that provides a dummy object to be provided as the in-out parameter and then discarded:
void Foo(Bar& b) { /* stuff */ }
void Foo() { Bar dummy{}; Foo(dummy); }
or since what you seem to want is a reference that can be null, stop using a reference and use the right language feature for passing something by reference that can be null instead:
void Foo(Bar* b) { /* stuff, updating b if not null */ }
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