On Wednesday, 2 January 2013 at 21:12:33 UTC, Maxim Fomin wrote:
On Wednesday, 2 January 2013 at 21:00:10 UTC, Michael wrote:
R  With(I, R)(I o, R function (I) fun)
{
        static if(isAssignable!(I, typeof(null)))
                return o is null ? null : fun(o);
        else
                return fun(o);
}

...

in main function
----------------
foreach(p; persons)     
        p.With((Person x) => x.address); // works

but
----------------
foreach(p; persons)     
                p.With(x => x.address); // error

nullcheck.d(89): Error: template maybe.With does not match any function template
declaration. Candidates are:
maybe.d(20):        maybe.With(I, R)(I o, R function(I) fun)
nullcheck.d(89): Error: template maybe.With(I, R)(I o, R function(I) fun) cannot
deduce template function from argument types !()(Person,void)


Why?

The first one is a lambda function, the second one is a lambda template. Templates have type void.

Actually the 'void' is just a diagnostics bug. (lambda templates only exist in template parameter lists.) The reason the matching fails is that IFTI is not smart enough to devise a type for the parameter 'x', and therefore no type for 'R' is obtained, what makes the matching fail. Currently other parameters are not taken into account during IFTI matching. I believe that the reason is that otherwise the compiler needs to be clever about the order in which it analyzes the parameters. I consider this one of the more annoying limitations.

A workaround that should work in this case is to use a template parameter:

auto With(alias fun, I)(I o) // maybe add a template constraint here
{
        static if(isAssignable!(I, typeof(null)))
                return o is null ? null : fun(o);
        else
                return fun(o);
}

---

foreach(p; persons)     
    p.With!(x => x.address);

This creates a template from the lambda, and instantiates it once inside 'With'. This way the return type does not have to be part of the template parameters.

Reply via email to