
Eric Niebler wrote:
David Abrahams wrote:
Eric Niebler wrote:
David Abrahams wrote:
Eric Niebler wrote:
-- snip 2^10 overloads --
Yeah, that's probably too much, but I'm not sure we have to support forwarding for that many arguments. The only thing rvalue forwarding buys you (and it can be a big win) is the ability for the wrapped thing to make certain optimizations. It's a good idea when you can do it. If you can't do it, you can fall back to lvalues and in C++03 you've still done a credible job. Even 2^3 overloads has a *very* noticeable effect on compile times.
8 overloads hurts compile times?
Yes, because for each function invocation you have to calculate the return type 8x in 8 different ways.
Hmm. Why? Seems to me that only one specialization of the wrapped class template needs to be instantiated per invocation.
I just think that since you don't have permission to mutate a const rvalue anyway, forwarding it as a const reference doesn't really hurt anyone. When I've gotten it wrong, it hurts. Maybe you're making assumptions that you really can't afford to make (that storing a reference to an lvalue, even when properly detected, is a good idea). Please, I'm not trying to detect lvalue/rvalue-ness!
I'm sorry if it sounded like you were being attacked; I was just trying to find an explanation for the hurt you described in the context of my understanding of the meaning of "const rvalue." Maybe where one really gets hurt is in dealing with return values: if you treat const rvalues as const lvalues you *will* dangle,
Yes.
and if you treat const lvalues as const rvalues you will cause the wrong semantics in way too many common cases.
Yes. I was trying to illustrate those points with the fusion::make_vector() example.
I think it's maybe better illustrated as template <class F, class T> result_of<F(T&)>::type forwarder(F const& g, T& x); If g(x) returns an rvalue, forwarder had better also return an rvalue or the result will dangle. if g(x) returns a const lvalue and forwarder does not, you can get silent odd behavior when the value returned from forwarder turns out to be a different object from the one g(x) references. Such functions can only work right if result_of returns the proper "reference-ness." However, there's no problem AFAICS with a forwarder like this, if it could be implemented. // Made-up syntax follows template <class F, class T> decltype(g(x)) forwarder(F const& g, T& x) if (x is an lvalue or const rvalue) { g( x ); } template <class F, class T> decltype(g(move(x))) forwarder(F const& g, T x) if (x is a non-const rvalue) { g( move(x) ); } for any sane implementation of F. That's my only point. It's not a big deal that we can't tell const rvalues from const lvalues where function arguments are concerned.
I'm letting users opt-in with reference_wrapper.
I understand that's the scope you chose. I was only trying to explore whether that facility can usefully be pushed a little further so that we don't lose move semantics inside of forwarded arguments. Well, I guess we don't, if we assume everything's an rvalue by default :-)
I'm not sure if changes are needed to better support move semantics, or what they would be. Feedback is welcome.
Basically, if your wrappers copy arguments by default, then it's always safe for wrapped functions to move from arguments unless they are reference_wrappers. We could even make move(x) where x is a reference_wrapper return an lvalue, so it'd be transparent. -- Dave Abrahams BoostPro Computing http://www.boostpro.com