
David Abrahams wrote:
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."
Correct. And the question raised in the "result_of and C++03" thread was: is the "reference-ness" of of result_of<F(T&)>::type allowed to be influenced by the "reference-ness" of the arguments in the function type. That is, what do these mean, are they different and if so, how? result_of<F(T)>::type // 1 result_of<F(T&)>::type // 2 result_of<F(T const&)>::type // 3 There be dragons there in C++03 because there's no way in C++03 to overload a function on T, T& and T const&. The only workable solution I've found so far is that these all mean the same thing: the result of calling F with an rvalue of type T, unless T is a reference_wrapper<U>, in which case, it's the result of calling F with an lvalue of type U. If your reaction is "yuk" then I agree, but I haven't yet thought of something better. Now, you might say that we can detect case (2) in C++03 and make it mean "lvalue of type T", but for functions that take N arguments, that leads us to 2^N overloads, and 2^N return type calculations, which I'm trying to avoid.
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.
Hm, I *think* I get it.
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,
They don't. They could, but I don't think they should, do you?
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.
I'm not seeing a win here, at least not for C++03. Little help? -- Eric Niebler BoostPro Computing http://www.boostpro.com