[Development] RFC: lambda or lambda return from lambda?

Sergio Martins sergio.martins at kdab.com
Mon Feb 1 13:34:05 CET 2016


On Monday, February 01, 2016 11:08:54 AM 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).

I would write:

removeIfFirstEquals(fields, name): because:

1) I could read it in English instead of very verbose C++
2) I would not need to read the implementation

And for the implementation.. it doesn't matter, it's a named function, only 
does one small thing and does it good.

About the inlining, which compilers don't and does it make a difference ? A 
function call should negligible compared to erase + remove_if 


Regards,
-- 
SĂ©rgio Martins | sergio.martins at kdab.com | Software Engineer
Klarälvdalens Datakonsult AB, a KDAB Group company
Tel: Sweden (HQ) +46-563-540090, USA +1-866-777-KDAB(5322)
KDAB - The Qt Experts



More information about the Development mailing list