Subject: Re: [boost] [range] adaptors vs. rvalue to lvalue& binding
From: Bronek Kozicki (brok_at_[hidden])
Date: 2012-03-22 11:44:06
On 22/03/2012 13:54, Arno Schödl wrote:
>>> Any thoughts? Should adaptors receiving lvalues offer an
>>> operator adaptor&()&&; // overload on rvalue-ness
>> you don't want to add such operator to any class, as it would trigger automatic conversion of rvalue of given type to lvalue.
>> Sometimes this is not right thing to do, but with added operator you will have no means of disabling this behaviour.
> Do you have an example for range adaptors where this is bad?
That would be anywhere when you are passing a temporary to function
taking lvalue-reference. If the actual parameter is indeed a temporary,
you may wish to apply rvalue-reference optimization, but with such an
interface you cannot, since you cannot tell whether actual parameter is
temporary or not. The only way to apply this optimization is to define
rvalue-reference overload, thus preventing the use of operator T& and
rendering it pointless.
Also, if such an operator is added to class interface, it would be
difficult to remove, since such change would break user code depending
on this particular implicit conversion.
> So do we want to change boost::sort( Rng& ) to boost::sort( Rng&& )
> ? That would make boost::sort( std::vector() ) ok.
I fail to see what's wrong with this. Pointless - yes, but inducing
runtime errors - no. Although of course I could have missed something.
Back to your function - perhaps taking unqualified template parameter
is not the best idea, and if you want to take a range you might want to
be bit more explicit about it? E.g. like this:
template<typename T1, typename T2>
void modifies_range(boost::joined_range<T1, T2> && rng);
I hope users of such "modifies_range" function would find nothing to
complain about such an interface.
> C++ decided at
> some point to disallow binding rvalues to lvalue&. I think the reason
> is that rvalues are inaccessible for the caller, so modifying them is
> likely a bug.
no, the reason was different. The function which takes rvalue-reference
does it in order to apply optimization (move semantics) which is
often/easily implemented as "stealing" data from its actual parameter.
If binding lvalues to rvalue-reference parameters was allowed, such
"stealing" could happen implicitly, on an lvalue parameter, and would
likely result in runtime errors. As things stand now, you have to be
explicit about moving data away from lvalues, e.g. by using std::move()
Also, there is nothing wrong with modyfying rvalues and in fact, move
semantics does exactly that. In fact, any member function can do that as
well, e.g. as "swap" does here, applied in a popular idiom:
// ... do some work and clean up afterwards
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk