Boost logo

Boost :

From: Daniel Walker (daniel.j.walker_at_[hidden])
Date: 2007-03-21 13:47:06


On 3/20/07, shunsuke <pstade.mb_at_[hidden]> wrote:
> Daniel Walker wrote:
> > In my patch for result_of, lack of support for has_template_xxx is
> > handled by checking BOOST_MPL_CFG_NO_HAS_TEMPLATE_XXX. In this case,
> > partial specializations for lambda::lambda_functor are provided so
> > that lambda expressions can be supported, even though user defined
> > functors using sig<> cannot. result_of already requires that the
> > compiler support partial specialization. So, to the best of my
> > knowledge, this doesn't add an additional limitation on the number of
> > compilers result_of can work on.
>
> If 'result_of' customization way is not enough,
> why not introduce a customization point.
> template<typename F, typename FArgs, typename EnableIf>
> struct extend_result_of;
> Then, the customizations for lambda is placed at
> <boost/lambda/result_of.hpp>.
> That's generics. :-)

This isn't a bad idea, but I feel that result_of is a simple utility
and doesn't merit an additional interface to provide for user
extension. Users should simply provide result<>. Boost.Lambda is a
special case partially because of long standing precedence and a large
user base. It's been around for ages. I like Giovanni's suggestion for
transitioning away from sig<> support. If/when lambda standardizes on
result<>, the lambda related special cases in result_of can be
removed.

>
> As I pointed, a lambda::functor doesn't need any patch.
> 'bind' turns a function using 'sig' into a lambda::functor.
> Thus, we have nearly everything without any patch.

With lambda functors exposing result<> you're right that you can use
lambda::bind to get the result_of::type of a function. However, this
involves a slight change in semantics. lambda::bind delays the call of
a functor, after all, which shouldn't be necessary to get the functors
return type. For example (this requires my lambda patch here
http://tinyurl.com/2jgtld) ...

#include <boost/lambda/bind.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/utility/result_of.hpp>
using namespace boost;

struct functor {
    template<class Args>
    struct sig {
        typedef typename tuples::element<1, Args>::type type;
    };

    template<class Arg>
    typename sig<tuple<functor, Arg> >::type
    operator()(Arg const& a) const
    {
        return a;
    }
};

template<class F, class Arg>
void g(F const& f, Arg& x)
{
    typename result_of<
        F(F, Arg)
>::type y = f(x);
}

int main()
{
    using namespace boost::lambda;

    typedef char value_type;
    value_type x;
    functor f;

    // Call f right away.
    result_of<
        functor(functor, value_type)
>::type y = f(x);

    // Delay call of f until later.
    g(bind(f, _1), x);
}

In the example above where functor f is lambda compatible according to
the existing convention, calling f right away causes an error without
the result_of patch even though delaying the call to f succeeds with
the lambda patch.

>
> On the other hand, "result_of<lambda>" project will be
> an interesting work. What does "result_of<bind(..)>" return?
> I want to know it :-)

This is kind of cool! First off, to literally use something like
'result_of<bind(functor)>::type' is illegal. Bind is not a constant
expression. result_of requires a function/functor type. I believe
Boost.Typeof can do this, though.

But in answer to your question the following illustrates the type of
result_of<>::type when applied to a lambda bound functor (this also
requires my new lambda patch).

#include <boost/lambda/bind.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits.hpp>
#include <boost/utility/result_of.hpp>
using namespace boost;

struct functor {
    BOOST_FIXED_ARITY_FUNCTOR_RESULT(2, A1)

    template<class Arg>
    typename result<functor(functor, Arg)>::type
    operator()(Arg const& a) const
    {
        return a;
    }
};

template<class F, class BoundF, class Arg>
void f(F const&, BoundF const&, Arg const&)
{
    BOOST_MPL_ASSERT((
        is_same<
            typename result_of<F(F, Arg)>::type
          , typename result_of<BoundF(BoundF, Arg)>::type
>
    ));
}

int main()
{
    using namespace lambda;

    typedef char value_type;
    value_type x;
    functor user_functor;
    f(user_functor, bind(user_functor, _1), x);
}

Note that if user_functor had used the existing lambda sig<>
convention (as is currently the common case among Boost.Lambda users)
this will not compile without the result_of patch.

Daniel


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