|
Boost : |
From: Eric Niebler (eric_at_[hidden])
Date: 2008-04-05 17:41:48
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
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk