General recommendations for the definition of lambda

Now that we can use lambdas C ++ 11 in our code base, we are trying to develop general principles for how they should be defined and used. I understand that there are, of course, subjective elements for this, but I think that there will probably also be some general rules that will be useful to the community.

What are the general principles for determining lambda?

  • When do you prefer to capture the link [&] or the value [=] ? What are the performance implications?
  • When do you prefer to explicitly commit a variable, for example [&foo] ?
  • Under what circumstances should you indicate the type of return? (C ++ 14 has better support for outputting return types than C ++ 11)
  • How complicated can a lambda be before it is better to rewrite it 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 that I am missing out on a few more powerful use cases.

+6
source share
4 answers

These questions are somewhat subjective, but I will take a picture:

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

  • Capturing a specific variable by reference if you need to change its value in the scope, but not the values ​​of other variables.

  • I try to always specify the type of the return value to increase readability (so that other people can immediately find out the type of the return value, instead of analyzing the lambda to output it).

  • The last of them is the most subjective of all, but I personally believe that lambdas larger than ~ 3-5 lines should be reorganized into functions, because long lambdas can reduce readability. However, there can be many exceptions, so this is more a matter of personal preference and depends heavily on the actual code.

+2
source

Many of these questions have answers based on the taste of the programmer and his code style.

When do you prefer to capture the link [&] or the value [=]? What are the performance implications?

You will capture with & if you want to modify the transferred object or do not want to make a copy. Otherwise, you can capture = .

When do you prefer to explicitly commit a variable, for example [& foo]?

If you just want to capture a specific object that you use [&foo] , you need to make your code more limited by simply passing a specific object, rather than [&] , to avoid unintentional errors.

Under what circumstances should you indicate the type of return?

You will determine the type of return (C ++ 11) when you need it. There is nothing special to advise.

How complicated can a lambda be before it is better to rewrite it as a function?

If you think a function is useful for reusing many functions, you should write it down as a normal function. Lambdas are usually useful for solving local requirements.

Use lambda when you need a simple predicate or comparator

Yes. Predicate or comparator functions, where they will no longer be reused, are a popular use case for lambda.

+2
source

In addition to other answers.

Use lambda when you need a simple predicate or comparator

Another useful pattern is to initialize const variables. Before lambdas, when initializing a variable became too complicated to fit a single expression, you had to either discard the constant or write a separate function that is used only once (which has other problems, for example, the need to pass arguments from the original scope).

Consider the following mute, extremely simplified example (suppose that initializing x cannot be rewritten as a single expression, because the if part if too complex):

 void foo(int y) { int x = 42; if (y > 42) ++x; // from now on we mustn't change x any more // but unfortunately it not const // use x } // or int init_x(int y) { // this function is only used once to initialize x in foo() // we could have many more parameters (not just y) int x = 42; if (y > 42) ++x; return x; } void foo(int y) { const int x = init_x(y); // use x } 

Now with lambdas you can get rid of an additional function, passing parameters and at the same time save the constant:

 void foo(int y) { const int x = [&]() { int x = 42; if (y > 42) ++x; return x; }(); // ^^ note: we call the lambda immediately // use x } 

Of course, this still obeys the usual β€œrules” about whether we can write code in a line or whether we need to make a separate function. But this perfectly solves those (many!) Cases where the initialization code would be complex enough to refuse a constant, but not complex enough to justify a single function.

+1
source

For the last question: a lambda function is essentially an anonymous function (a function without a name) that is defined in a string. Its incredibly useful when you need a little function that doesn't really justify declaring and defining a normal function. A typical example where a lambda function is convenient is something like a comparison passed to std :: sort. For instance:

 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; } 
0
source

Source: https://habr.com/ru/post/958847/


All Articles