Boost logo

Boost :

Subject: Re: [boost] [range] adaptors vs. rvalue to lvalue& binding
From: Arno Schödl (aschoedl_at_[hidden])
Date: 2012-03-25 13:29:53


Hello,

>> If the solution is>
>>
>> template<typename Range>
>> boost::sort( Range && );

> I think the interesting question is really: what should boost::sort
> return?

Let's try to be more general.

- There are read-only functions like boost::accumulate.

- There are range-transforming functions, taking a range and returning a range. I think it is a discussion for a separate thread whether they are always lazy (like adaptors) or sometimes eager (boost::sort?).

- And there are range-mutating functions. boost::for_each is currently an example, the range may be modified but is not returned. Many functions in application code also fall into this category.

A ) We probably agree that we want to be able to stack transforming functions and use them with rvalues:

adaptors::transform(adaptors::reverse( vector<int>() ), func);

B) We probably also agree that a mutating function can take a transformed lvalue:

vector<int> vec;
for_each( adaptors::transform(vec, func), mutating_func() ); // must compile

C) And we would probably prefer that a mutating function cannot take an rvalue:

for_each( vector<int>(), mutating_func() ) // must not compile

D) even if this rvalue is transformed:

for_each( adaptors::reverse(vector<int>()), mutating_func() ) // must not compile

E) Read-only functions should not be able to modify their argument, even if it is transformed:

vector<int> vec;
accumulate(adaptors::reverse(vec), 0, mutating_func() ) // must not compile

If, as Bronek et. al. propose,
- read-only functions take ranges by const&,
- transforming functions take ranges by && and
- mutating functions take ranges by &&,
A and B and E are fulfilled. C and D are not.

If, as I understand your proposal,
- read-only functions take ranges by const&
- transforming functions take ranges by &&, and
- mutating function take by ranges &, and
- t adaptors return const rvalues with range_iterator<const Range>::type mutable,
A, B and C are fulfilled. D and E are not.

If we change it to
- read-only functions take ranges by const&,
- transforming functions take ranges by &&, and
- mutating function take by ranges &, and
- adaptors return const rvalues with range_iterator<const Range>::type mutable _only if their input was an lvalue&_
A, B, C, and D are fulfilled, but still not E.

My proposal,
- read-only functions take ranges by const&,
- transforming functions take ranges by &&, and
- mutating function take by ranges &, and
- adaptors are convertible to lvalue& if their input was an lvalue&
fulfills A, B, C, D and E, but unfortunately, does not work, because it looks like when matching a template, conversion operators are not considered:

struct A {
        operator A&() const { // should be && but unsupported
                return const_cast<A&>(*this);
        }
};

void foo( A& a ){}
template< class T > void bar( T& t ){}

int main() {
        foo(A()); // ok
        bar(A()); // does not compile
        return 0;
}

My personal opinion is that respecting constness, E, are more important than respecting rvalueness, C and D.

What do you think? Are the requirements reasonable? Any more proposals?

Regards,

Arno

--
Dr. Arno Schödl | aschoedl_at_[hidden]
Technical Director
think-cell Software GmbH | Chausseestr. 8/E | 10115 Berlin | Germany
http://www.think-cell.com | phone +49 30 666473-10 | US phone +1 800 891 8091
Amtsgericht Berlin-Charlottenburg, HRB 85229 | European Union VAT Id DE813474306
Directors: Dr. Markus Hannebauer, Dr. Arno Schoedl

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk