Boost logo

Boost :

From: Daniel Walker (daniel.j.walker_at_[hidden])
Date: 2007-03-22 11:38:53


On 3/22/07, shunsuke <pstade.mb_at_[hidden]> wrote:
> Daniel Walker wrote:
> > On 3/21/07, shunsuke <pstade.mb_at_[hidden]> wrote:
> >> Daniel Walker wrote:
> >>> If/when lambda standardizes on
> >>> result<>, the lambda related special cases in result_of can be
> >>> removed.
> >> It will break a code using not result_of but sig compatible functors?
> >
> > Yes. That's the reason lambda would support both for a time with sig<>
> > being deprecated. After a release or two (giving users plenty of time
> > to update their code) sig<> would be removed. This gives them a fair
> > warning and time to adapt.
>
> I think users don't want to spend the time.
> Smart users will protect themselves right now by using something like..
>
> struct sig_compatible_fun
> : enable_result_of_sig // added
> {
> // ...
> };
>
> Hmm, patch is no longer required. :-)

There are lots of ways that users can work around the fact that
result_of can't work with lambda. We've discussed several. There are
usually ways for users to work around missing features and/or bugs in
the 3rd party libraries they use.

The point of my patches are to make result_of work with lambda without
requiring additional user effort. I believe this is a reasonable
expectation. I first ran into this problem because the Boost.Parameter
library explicitly told users to use lambda and then passed the lambda
functor to result_of. When it didn't work, it appeared like a bug in
the parameter library. So, I think it is not an uncommon
disappointment among boost users and developers that lambda and
result_of don't play nicely together out of the box.

Plus, as Eric pointed out earlier in this thread, the result_of
convention of using result<> for return types is now standard (is that
TR1?). Why shouldn't lambda follow it?

An alternative might be to leave result_of unchanged but provide a
converter along the lines of your suggestion: a function adapter that
would make lambda expressions usable in result_of. Boost users could
use this with lambda expressions and their own lambda compatible
functors. Boost.Parameter could use it to make lazy binding work as
advertised. However, in the long run it seems like there should be a
single convention for specifying argument dependent return types using
result<>, and user expectations such as boost libraries being
interoperable should be met as much as possible.

>
> >> Can the patch support a sig compatible functor
> >> which is "nullary-callable" (e.g. lambda::constructor<>) ?
> >
> > Yes. I just tested it with lambda::constructor<>, and it does work.
>
> I tried this:
>
> #include <boost/utility/result_of.hpp>
> #include <boost/lambda/construct.hpp>
>
> int main()
> {
> using boost::lambda::constructor;
> using boost::result_of;
>
> int i = 1;
> result_of<constructor<int>(int&)>::type
> r = constructor<int>()(i); // (1) GCC compiles.
>
> result_of<constructor<int>()>::type
> r = constructor<int>()(); // (2) GCC fails.
> }

I missed this. I tested with something like ...

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

int main()
{
    using namespace lambda;
    f(bind(constructor<int>()));
}

... which works due to the resul_ot patch, not the lambda patch. I'll explain.

As I understand it, the problem here is two fold. First, the result_of
documentation states that:

"result_of<F(T1, T2, ..., TN)> is F::result<F(T1, T2, ..., TN)>::type
when N > 0 or void when N = 0."

So, any nullary result_of<F()> will be void unless F provides
result_type. The same is true if F provides sig<>... with one
exception: if F is generated from a lambda expression result_of<F()>
will deduce the correct type. constructor<> isn't a lambda expression.
It's a wrapper class that can be used as a target function of
lambda::bind expressions.

Second, I inadvertently made the type deduction in result_of more
powerful for lambda expression than the usual functors. It can
correctly deduce the return types of a lambda::lambda_functor taking
zero or more arguments. result_of can not deduce the return types of
any arbitrary functor F which overrides operator() for zero or more
arguments due to the fact that when the number of arguments for
F::result<F()> is zero result_of always evals to void. You can't
supply a F::result_type for this case because it will be preferred
over the F::result<> for the operator()s that take arguments.

It seems to me that this limitation is simple to overcome if you make
result_of dependent on whether the functor provides a result_type or
result<> (or sig<>) instead of the number of arguments. The
documentation would read something like the following.

"When F is a class type with a member type result_type,
result_of<F(T1, T2, ..., TN)> is F::result_type. Otherwise, if F is a
class type with a member type F::result<F(T1, T2, ..., TN)>::type,
result_of<F(T1, T2, ..., TN)>::type is F::result<F(T1, T2, ...,
TN)>::type. Otherwise, result_of<F(T1, T2, ..., TN)>::type is void for
N >= 0."

The third case could be changed to be dependent on the number of
arguments (after giving the user a chance to supply result_type or
result<>) if that's preferable. This is simple to implement with
has_template_xxx. Am I missing something?

If it's impossible to make the above changes due to the fact that the
behavior has already been standardized, I could instead provide
specializations for result_of with nullary lambda expressions (and
helper classes like construct) in the lambda library and get the same
effect. This is what Douglas suggested for users to do in the
rationale sited below.

>
> I guess a sig-compatible functor which is nullary-callable must be
> ported to result_of, even if the patch is applied.

The same is true for a result-compatible functor as described above.
This is an existing limitation of result_of which we may or may not
want to address.

>
> Note that nullary instantiation of 'result_of' must always succeed.
> (See the rationale at
> http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1454.html)

I believe the errors you're seeing are due to the assignment to r
(which is declared void) and not to result_of<constructor<int>()>
being ill-formed.

>
> Well, I have bad news. VC++7.1 and VC8 can't compile (1) nor (2). :-(

Could you send the error messages you're getting for (1)? (2) won't
compile due to the limitation that result_of always ignores nullary
F::result<F()>::type.

>
> >> I introduce <boost/detail/functionN.hpp> at Boost.Accumulators,
> >> which seems very cool.
> >
> > I looked for your file in the boost-sandbox cvs repository and
> > couldn't find it. Could you send a link?
>
> See the accumulators.zip in "Math - Numerics" directory at Boost Vault.

I'll check it out.

Thanks again!
Daniel


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