Boost logo

Boost :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2001-10-10 14:06:00


From: "David Abrahams" <david.abrahams_at_[hidden]>
> Could you please elaborate on this post? I'm very interested in what
you're
> saying here, but I don't understand any of it!

Sure!

Suppose that you have a function object f of type F and you need to create
another function object g such that g(x) is exactly equivalent to f(x).

For instance, when you say bind(f, _1), bind has to create that g and return
it.

(This is the minimal example that illustrates the point.)

In order to define g, you need to be able to:

1. Accept any argument and pass it to f unmodified (without adding any const
qualifiers or turning it into a pass-by-value, because this would change the
meaning.)

2. Somehow infer the return type of f(x) (given the type of x) so that you
can declare your operator().

Or, in pseudocode:

struct G
{
    template<class T> typeof(f(x)) operator()(T & x) const { return f(x); }
};

assuming that T & x is fixed to accept non-const temporaries.

A full-fledged lambda library needs to solve a variety of similar problems;
when you say _1 + _2 this means "give me a function object 'plus' such that
plus(x, y) is equivalent to x + y for any x and y."

The _1 << _2 example (that I gave in the previous post) is interesting,
because it returns by value when the first argument is integral, but by
reference when the first argument is std::ostream.

I'm sure that Jaakko and Gary can explain why C++ needs a typeof operator
much better than me. :-)

Once you have a solution to these two problems, working with arbitrary
function objects becomes straightforward. A projection_iterator can simply
use typeof(f(*it)) to infer its value_type; moreover, the whole concept of
Iterator::value_type becomes redundant - you can use typeof(*it) to
determine it.

--
Peter Dimov
Multi Media Ltd.

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