Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2008-05-01 14:56:22


on Tue Apr 29 2008, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:

> 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.

Ah, but I think you miss the point. I need the specializations to
handle all the different CV-qualifications of the *function object*. I
suppose if you have full control over the function object you can do it
with a nested result<>, and now I forget why I might not have wanted to
do that. Perhaps I just didn't want to force F to be instantiated when
checking its result 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();
> }

Fine, then take the case where call takes f by value; then F can be a
function type and result_of<F()> is illegal.

Because function call operators have to be member functions in C++03, an
lvalue function object must behave the same as an rvalue, so

  result_of<T()>::type == result_of<T&()>::type

is an invariant. That means I can afford to always add a reference, but
it's still painful:

     typename result_of<typename boost::add_reference<F>::type ()>::type

> 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.

Ouch.

> Of course, that opens another can of
> worms, if you'd like to preserve the polymorphic behavior of
> overloaded/templated built-ins.

Well you can't handle that case anyway; an overload set or a template
doesn't have a type that can be passed on to result_of.

-- 
Dave Abrahams
Boost Consulting
http://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