$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [boost] [range] adaptors vs. rvalue to lvalue& binding
From: Bronek Kozicki (brok_at_[hidden])
Date: 2012-03-22 06:30:06
On 22/03/2012 06:40, Arno Schödl wrote:
> Hello,
>
> ideally I would like to use range-adapted lvalue ranges like any
> other lvalue ranges. Writing it down naively, as below, does not
> compile because LoadRefRange takes (and should take?) the range it
> modifies by lvalue&, while adaptor expressions are rvalues.
>
> template<typename Range>
> void modifies_range( Range&  rng );
>
> A a[5];
>
> main() {
>        // modifies all elements of a
> 	modifies_range ( a );
>
>        // modifies all elements (except for one) of a
> 	// adaptor is rvalue, does not compile:
>        modifies_range (
> 		boost::range::join(
> 			boost::adaptors::slice( a, 0, 1 ),
> 			boost::adaptors::slice( a, 2, countof(a) )
> 		)
>        );
>
> 	// compiles, but ugly:
> 	auto rng=boost::range::join(
> 		boost::adaptors::slice( a, 0, 1 ),
> 		boost::adaptors::slice( a, 2, countof(a) )
> 	);
> 	modifies_range(rng);
> }
>
>
> Any thoughts? Should adaptors receiving lvalues offer an
>
> operator adaptor&()&&; // overload on rvalue-ness
Hello
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. Apart from that, ref-qualifiers 
unfortunately are not yet widely implemented and such code won't be very 
portable anyway (I only know of 2 compilers implementing this feature).
What you want to do instead is to change the signature of your function 
to accept both lvalue and rvalue reference:
   template<typename Range>
   void modifies_range(Range && rng);
I know it seems counter-intuitive since only && is used above, but it 
will work with both lvalues and rvalues thanks to reference collapsing 
rules. When Range is a reference type, && following it will do nothing 
(being collapsed) and lvalue binding will apply; when Range is an rvalue 
you will have proper rvalue binding; in both cases parameter "rng" is 
always an lvalue when used inside the function, since it's named; also 
in both cases rvalue-sness or lvalue-sness of actual function parameter 
is preserved in type Range, so it can be "recovered" e.g. with 
std::forward<Range>(rng).
You can find more detailed explanation of how this works on Thomas 
Becker's explanation of rvalue-references:
http://thbecker.net/articles/rvalue_references/section_08.html
B.