|
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