
Peter Dimov wrote:
Eric Niebler: ...
Like a good citizen, I've written make_foo's function call operator to recognize reference_wrapped and non-const-ref arguments as representing lvalues and all others as rvalues.
Const-ref arguments are lvalues. I'm not sure why do you need the reference_wrapper support.
Not so. make_foo()(1) -- 1 binds to the const-ref, but it is not an lvalue.
The strictly correct thing to do would be to wrap lvalues in reference_wrappers before passing them to F. If I don't, make_foo will do the wrong thing.
I don't see why. Lvalues are lvalues. Wrapping them in a reference_wrapper won't make them any more lvaluish. I'm probably missing something.
Indeed.
struct blarg { template<typename This, typename Arg> struct result< This( Arg ) > { // OK, if Arg is a reference, then it's an lvalue! };
template<typename Arg> typename result< make_foo( ??? ) >::type operator()( Arg const & arg ) { // whoops, I don't know here if arg is an lvalue or rvalue } };
Write the return statement. Is it
return make_foo()( arg );
?
I clearly should have fleshed this out a bit more. Consider something like a fusion::make_tuple function object struct make_tuple { template<typename Sig> struct result; template<typename This, typename Arg> struct result< This( Arg ) > { typedef tuple< Arg > type; }; // This is wrong! template<typename Arg> typename result< make_tuple( Arg const & ) >::type operator ()( Arg const &arg ) { return tuple< Arg const & >( arg ); } }; This is wrong because make_tuple(1) will cause the resulting tuple to hold on to a dangling reference. But had it been called as: int const i = 0; make_tuple( i ); ... then it's correct. The problem here is that make_tuple::operator() can't know whether it was passed an lvalue or an rvalue, so it doesn't know how to compute the return type. In contrast, the result<> template knows, because you can explicitly specify lvalue or rvalue as: // lvalue: result_of< make_tuple( int const & ) >::type // rvalue: result_of< make_tuple( int ) >::type It is for this reason that Fusion's make_tuple() function (it doesn't have a function object -- I consider that a defect) recognizes reference_wrapped objects to be lvalues. There's no other way to distinguish them in C++03. -- Eric Niebler Boost Consulting www.boost-consulting.com