Boost logo

Boost :

From: Daniel Walker (daniel.j.walker_at_[hidden])
Date: 2008-04-29 14:04:54


On Tue, Apr 29, 2008 at 5:43 AM, David Abrahams
<dave_at_[hidden]> wrote:
>
> The difficulty of implementing the result_of protocol has always
> bothered me. I've often found myself writing a primary result<...>
> template and several specializations to handle different
> cv-qualifications, and I've still not felt that I was doing it quite
> right.

Yes, I think that's the right way to do it. My understanding is that
every time you write a new overload, you need to write a new
specialization of result<> for that overload, whether you're
overloading on arity, type, cv-qualification, etc. You have to
advertise the return type of each function definition that the
compiler could choose during overload resolution; i.e there's always a
one-to-one correspondence between result<> specializations and
function overloads. So, there's one more regular step to take when
defining a function overload - whenever you define a return type in
the overload's prototype, also advertise that return type by
specializing result<> for the overload. I guess this can become
habitual, but like all manual processes, I can see how this poses an
opportunity for human error. The result_of<> documentation doesn't
address these use-cases at all, so that's no help. Maybe Egg could be
of help, but it may have some usability issues of its own. Of course,
the ultimate solution is the C++0x result_of that works by
fiat/decltype.

<snip>
> template <class F>
> typename result_of<F()>::type
> call(F const& f)
> {
> return f();
> }
>
> int f() { return 0; }
>
> int x = call(f);
>
> The problem is that in the above case, F is deduced as int(), and we
> form an illegal function type (one that itself returns a function type)
> in result_of<F()>::type.
>
<snip>
> Is there an easier way?

Yes, I believe so. The result_of documentation says that for a
callable object f of type F you have result_of<F()>::type. So, I think
one should use the exact type in situations like this. In your example
above, f is a F const&, so...

template <class F>
typename result_of<F const&()>::type
call(F const& f)
{
    return f();
}

I tried this with gcc 4.3, and it works with your example. However, I
don't think this is a perfect approach for passing arbitrary callable
objects. I confess I don't know all the issues off the top of my head,
but I believe a better approach is to have call() accept only
full-blown, first-class function objects as arguments. If users would
like to pass built-in functions, they should first promote them to
first-class function objects using boost::function/std::function. Of
course, that opens another can of worms, if you'd like to preserve the
polymorphic behavior of overloaded/templated built-ins.

Daniel Walker


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