|
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