
On Thu, Apr 10, 2008 at 12:00 PM, Eric Niebler <eric@boost-consulting.com> wrote:
shunsuke wrote:
Eric Niebler wrote:
As shown above, lvalue/rvalue-ness doesn't guarantee the complete safety. I think your argument is specious.
I just show a counter-example. It might not be a real use case, though. I think
int i; /* perform elaborate calculations for i. */ return make_tuple(rvalue(i));
seems odd.
I actually agree. I've looked again at fusion::make_tuple and I see I misremembered its behavior. It always stores arguments by value unless the argument is a reference_wrapper. That seems reasonable, even in C++0x.
So maybe I'm coming around to thinking that function objects that do something different with lvalues and rvalues are always a bad idea, even in C++0x. Not sure yet what the implications are for proto transforms.
Yeah, I have the same intuition about treating them differently. I haven't looked closely enough at proto to appreciate the dangling reference issue that led to the differentiation between lvalues and rvalues, but my gut tells me that if at all possible it's better not to worry about whether the references are to temporaries/rvalues or not; instead, focus on the copyability and modifiability of function parameters... For C++03 call-by-reference functions, rvalue arguments bound to references are never copied and are never modifiable. For C++0x call-by-reference functions, rvalue arguments bound to references are never copied, but with the new rvalue references, they can be modifiable. For both standards, of course, call-by-value functions always copy their arguments and may modify the copies. So, following fusion::tuple's example in a way, by adopting a call-by-value convention for all functions there would be no more references to dangle. Then the problem is copying objects. However, that's exactly the problem reference_wrapper solves - it allows the caller to make a call-by-value function act as if it's call-by-reference, and it puts the responsibility of managing the lifetime/validity of the reference in the hands of the caller. Under this scenario, reference_wrappers would not be a convention for representing lvalue/rvalue-ness but simply referenceness; i.e. whether the parameter is copied. Something along these lines would be safe, at least as safe as fusion::tuple, and would be forward compatible. However, in order to take advantage of the new C++0x rvalue references, Boost.Ref would need to be extended with new functions along the lines of Shunsuke's rvalue(), say rref() and crref(), which would be the rvalue counterparts of ref() and cref() - i.e. they would generate reference_wrappers with implicit conversion to T&&. I don't think this would require an entirely new wrapper template, but it might. FWIW, those are just some thoughts. I can't judge whether this would be suitable for proto or not. Thinking about this, though, it seems to me that extending boost ref to handle rvalue references should probably be under consideration as more C++0x compilers come to life. Daniel