[Development] RFC: lambda or lambda return from lambda?
Jędrzej Nowacki
jedrzej.nowacki at theqtcompany.com
Mon Feb 1 10:18:25 CET 2016
On Monday 01 of February 2016 11:08:54 Marc Mutz wrote:
> Hi,
>
> We're seeing increasing use of lambdas in dev, and I'm a bit unhappy about
> the result.
>
> E.g. (not picking on Anton here, I have done the same before):
>
> auto firstEqualsName = [&name](const QPair<QByteArray, QByteArray> &header)
> {
> return qstricmp(name.constData(), header.first) == 0;
> };
> fields.erase(std::remove_if(fields.begin(), fields.end(),
> firstEqualsName),
> fields.end());
>
> This is one way to write a unary predicate. But it hides the fact that the
> predicate depends on the parameter 'name' (an argument to the function this
> lambda is defined in).
>
> With classical function objects, one would have written - at the call site:
>
> fields.erase(std::remove_if(fields.begin(), fields.end(),
> FirstEquals(name)),
> fields.end());
>
> See the difference?
>
> Now, we don't want to go back and write function objects for one-time use,
> but it would be nice to have this explicit syntax, would it not?
>
> One way to have this with lambdas is to write a lambda that returns a
> lambda. We can do this, because auto return type deduction works for
> lambdas already in C++11, unlike for normal functions. With this, the above
> would become (hold tight):
>
> auto firstEquals = [](const auto &name) {
> return [&name](auto header) { return qstricmp(header.first, name) == 0;
> }; }
>
> where I used auto and dropped the const-& argument passing only for
> exposition, to get it onto a single line.
>
> fields.erase(std::remove_if(fields.begin(), fields.end(),
> firstEquals(name)),
> fields.end());
>
> So, where to put the ugliness: on the definition of the lambda, or the call
> site? (Note that "if you use this lambda more than once, then X" is not a
> good answer, because you shouldn't use lambdas more than once. But with the
> lambda- returning-lambda, you could actually reuse them:
>
> // at global scope:
>
> auto firstEquals = [](const auto &name) {
> return [&name](auto header) { return qstricmp(header.first, name) == 0;
> }; }
>
> // use in several functions - always the same type
>
> Whereas without the outer lambda, each use would create a new type, and
> potentially duplicate code (same problem as QStringLiteral, and the same
> soultion, really: wrap them in a function, except for lambdas, because of
> the unnameable return type, we need to use another lambda instead of a
> classical function).
>
> So, which one to use?
>
> Thanks,
> Marc
Hi,
I would just inline the lambda inside remove_if. That way "name" would be
explicit in place in which it is used and you could avoid 2nd lambda.
So it would look like that:
fields.erase(std::remove_if(fields.begin(),
fields.end(),
[&name](const QPair<QByteArray, QByteArray>
&header)
{
return qstricmp(name.constData(),
header.first) == 0;
}),
fields.end());
// I hope that formating is still ok, and the code is not wrapped.
For a bigger code we would actually require named functions. What do you
think?
Cheers,
Jędrek
More information about the Development
mailing list