Subject: [boost] [lambda] [result_of] Lambda enhancements
From: Adam Butcher (dev.lists_at_[hidden])
Date: 2010-04-01 13:46:08


Hi

Perhaps this would have been better as two separate mails but since it
is all lambda related I have included it as one (despite one patch
actually being to the result_of library).

[lambda]

I discovered recently that member-function-ptrs wrapped in boost::lambda
objects do not apply directly if the subject is held in a smart-ptr
(unless that smart-ptr has an implicit conversion to T*). There are a
number of places in our code base where we have worked around this by
using something like *free1 rather than simply free1 which ends up
calling the 'apply member-function to object-by-reference' adaptor.
This works providing the smart-ptr defines a type 'element_type' to be
the underlying object type (as shared_ptr et al do). It does not work
for third-party smart-ptrs that do not define this type.

It struck me that since boost.bind uses boost.mem_fn's get_pointer
template to handle this use case it would be reasonable to add an
overload of 'apply' to lambda/detail/function_adaptors.hpp that deferred
to that. I knocked up a perl script which adds the necessary overloads
to each specialization in function_adaptors which I have attached (I
have also attached the resulting diff). It may be that this yields some
unpleasant side-effects that I haven't thought of or observed but so far
it seems to work okay with our code base. The get_pointer overload is
disabled if the argument is convertible to ref-to-const-object-type
(e.g. if it is a derived type) since then the reference overload should
be used. I would appreciate any feedback on the idea and
implementation.

[result_of]

Whilst implementing a front-end template for a set of functions that
accept boost.function objects with various return types, I discovered
that boost.result_of does not implement support for the nested
sig<tuple> template used by boost.lambda objects. My intent was to
accept any user-supplied function at the front-end and, based on the
given function's return type when applied to a specific set of
arguments, forward to the appropriate implementation. This
determination currently fails if the user supplies a lambda object.

The attached result_of patch adds detection of the nested sig template
in order to support determining the return type of lambda functions
(providing the necessary arguments are given). This is done in a
non-intrusive way; i.e. there is no physical dependency on boost.lambda
or boost.tuple, though the boost.tuple classes 'cons' and 'null_type'
are forward declared. Since they are only ever instantiated when a
boost.lambda object is provided (which will have already brought in
their definitions) I think it should be okay. In order to provide the
sig template with its required tuple, a facility has been added (with
implementation generated by some additional preprocessor code) that
converts from function-type to tuple (i.e. F(A,B...) -> cons<F,cons<A,
cons<B,...null_type>>>). Since only the type declarations are required
this can be done without pulling in any tuple headers.

One thing I am a little concerned about is that the determination
mechanism for the existence of the sig template is probably not very
portable (I have only tried it on GCC 4 and VC9).

Is there an MPL/type_traits predicate generator for portable nested
template detection? I am aware of BOOST_MPL_HAS_XXX_TRAIT_(NAMED_)DEF
but I couldn't see any generator around that area that would do nested
template detection. We have such a facility in our code base but it
will have only been tried on GCC 4 and VC9 (maybe also VC7.1).

Again I would appreciate any feedback on these diffs and whether or not
they are suitable for inclusion into the respective libraries.

Regards,
Adam