Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using rvalue references for default arguments

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.

like image 555
Matt Kline Avatar asked Aug 11 '14 21:08

Matt Kline


People also ask

When should a function take rvalue reference?

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 .

What are rvalue references good for?

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.

How do you use rvalue reference?

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&& .

Can rvalue references bind to Lvalues?

An lvalue reference can bind to an lvalue, but not to an rvalue.


1 Answers

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 */ }
like image 86
Jonathan Wakely Avatar answered Oct 15 '22 20:10

Jonathan Wakely