Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

General guidelines for defining lambdas [closed]

Tags:

c++

c++11

lambda

Now that we're able to use C++11 lambdas in our codebase we're grappling with working out the general principles of how they should be defined and used. I realise that there are certainly subjective elements to this, but I think there are also likely to be some more general rules of thumb that will be useful to the community.

What are the general principles of defining a lambda?

  • When should you prefer to capture by reference [&] or value [=]? What are the performance implications?
  • When should you prefer to capture a variable explicitly, eg [&foo] ?
  • Under what circumstances should you specify a return type? (C++14 has better support for inferring return types than C++11)
  • How complex can a lambda be before it's better being rewritten as a function?

Personally, my general principle at the moment is 'Use a lambda whenever you need a simple predicate or comparator', but this may mean I'm missing out on some much more powerful use cases.

like image 877
the_mandrill Avatar asked Nov 26 '13 10:11

the_mandrill


3 Answers

These questions are somewhat subjective, but I'll give it a shot:

  • Capture by reference when you need to modify the values in the enclosing scope (obviously), or when you want to avoid copying heavy variables; capture by value otherwise.

  • Capture a specific variable by reference if you need to modify it's value in the enclosing scope, but not the values of other variables.

  • I try to always specify the return type to increase readability (so other people can immediately know the return type, instead of having to parse the lambda to deduce it).

  • The last one is the most subjective of all, but I personally think that lambdas bigger than ~3-5 lines should be refactored to functions, because long lambdas can reduce readability. However, there can be many exceptions, so this is rather a matter of personal preference and highly depends on the actual code.

like image 195
SingerOfTheFall Avatar answered Sep 21 '22 02:09

SingerOfTheFall


Many of those questions have answers based on programmer's taste and his code style.

When should you prefer to capture by reference [&] or value [=]? What are the performance implications?

You will capture by & when you want change the passed object or you don't want make a copy. Otherwise you can capture by =.

 

When should you prefer to capture a variable explicitly, eg [&foo] ?

If you want just capture a specific object you use [&foo], it's up to you to make your code more restrict by just passing specific object rather that [&] to avoid unintended mistakes.

 

Under what circumstances should you specify a return type?

You will determine a return type (C++11) when you need it. There is no special thing to advise.

 

How complex can a lambda be before it's better being rewritten as a function?

If you think a function are useful to be reused over many functions you should write it as a normal function. Lambdas usually are useful to solve a local requirement.

 

Use a lambda whenever you need a simple predicate or comparator

Yes. The predicate or comparator functions where they will not be reused anymore are the popular case to use lambdas.

like image 36
masoud Avatar answered Sep 22 '22 02:09

masoud


For your last question: A lambda function is essentially an anonymous function (a function without a name) that’s defined inline. It’s incredibly useful for when you need a small function that does not really seem to justify declaring and defining a normal function. The typical example where a lambda function is handy is for something like a comparison being passed to std::sort. For example:

struct Apple
{
   Apple(double weight, int age) :
      m_weight(weight),
      m_age(age)
   {}

   double m_weight; 
   int m_age; 
};

int main()
{
   vector<Apple> myApples;
   myApples.push_back(Apple(0.30, 30));
   myApples.push_back(Apple(0.75, 80));
   myApples.push_back(Apple(0.55, 90));

   sort(myApples.begin(),
        myApples.end(),
        [](const Apple &a, const Apple &b) -> bool
        {
           return (a.m_weight < b.m_weight);
        });

   return 0;
}
like image 25
zangw Avatar answered Sep 24 '22 02:09

zangw