Boost logo

Boost :

From: Eric Niebler (eric_at_[hidden])
Date: 2008-07-01 15:22:19


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.

>> David Abrahams wrote:
>>> Can you show me an example of a "sound" function that treats a const
>>> rvalue differently from an lvalue, please?
>> fusion::make_vector(), for instance. It returns a fusion::vector<> where
>> the members can be held by value or by reference. Getting it wrong can
>> lead to dangling references. Proto has similar function objects that
>> need to be careful about the lifetime of temporaries.
>
> I'm a little confused.
>
> Proper rvalue detection for *wrapper functions* or not, we have no way
> of writing make_vector so that it stores all rvalues and references
> lvalues. So in C++03, that function needs some hints about when to
> store values.

Of course.

> I'm not convinced it doesn't need those hints in C++0x.

Right.

> After all, any time you build a vector of references from lvalues, those
> references (or copies thereof) can be made to dangle.
>
> That doesn't mean a wrapper function should not forward non-const
> rvalues to its wrapee.

The wrapper I wrote (poly_function) passes arguments to the wrapped
function and also passes along information about whether the user
specified that argument as an lvalue (reference-wrapped) or not. That's
all. Whether the wrapped function *actually* accepts its (rvalue)
arguments as "T" or "T const &" is a different issue. poly_function
doesn't care.

When you use poly_function, you basically write a template that
generates mono-morphic function objects like this:

template< class Arg0, class Arg1 >
struct my_function
{
     typedef ... result_type;

     result_type operator()(poly_arg<Arg0> a0, poly_arg<Arg1> a1) const
     { ... }
};

If ArgN is a reference, then the user has reference-wrapped the
argument. If it isn't a reference, it was passed unwrapped.

What poly_function buys you is:

1) It implements the result_of protocol for you, correctly handling
const, refs, and reference wrappers.

2) It unwraps any reference wrapped args before forwarding them.

3) It makes writing a polymorphic function object as simple as writing a
monomorphic one.

>>>> It wouldn't be useful for
>>>> my purposes. What I took from the discussion about result_of and C++03
>>>> was that, for a function object that cares about lvalue/rvalue-ness to
>>>> work consistently across C++03 and C++0x, assuming rvalue-ness and
>>>> opting in for lvalue-ness with reference_wrapper<> is really the only
>>>> option. But if you have an insight, I'd be happy to reopen that
>>>> discussion. It was rather unsatisfying last time.
>>> 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 letting users
opt-in with reference_wrapper.

-- 
Eric Niebler
BoostPro Computing
http://www.boostpro.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk