Lambda: Why are values ​​bound by const value, but record values?

Why are values ​​bound by const value, but there are no objects bound to a link:

int a; auto compile_error = [=]() { a = 1; } auto compiles_ok = [&]() { a = 1; } 

It seems illogical to me, but it seems to be the standard? Moreover, an undesirable modification of a captured value can be an annoying mistake, but there is a chance that the consequences are limited by the scale of the lambda, while an undesirable modification of objects captured by a link often leads to more serious consequences.

So why not lock the const link by default? Or at least support [const &] and [&]? What are the reasons for this design?

As a workaround, you should probably use std :: cref wrapped const links captured by the value?

+6
source share
3 answers

Say you are fixing a pointer by value. The pointer itself is a constant, but there is no access to the object it points to.

 int i = 0; int* p = &i; auto l = [=]{ ++*p; }; l(); std::cout << i << std::endl; // outputs 1 

This lambda is equivalent to:

 struct lambda { int* p; lambda(int* p_) : p(p_) {} void operator()() const { ++*p; } }; 

const on operator()() makes using p equivalent to declaring it as:

 int* const p; 

This happens with reference. The link itself is "const" (in quotation marks because the links cannot be reviewed), but access to the object to which it refers is not.

+7
source

Captured links are also const . Rather, links are always implicitly const - there is no syntax in the language that allows you to change the link location. a = 1; when a is a link does not change the link, but changes what the link refers to.

When you talk about "const reference", I think you're confused. You are talking about a "reference to const int" ( const int & ). "Const" here means the thing referenced, not the link itself. It is similar to pointers: with a "pointer to const int" ( const int * ), the pointer itself is not const - you can assign a variable of this type whatever you want. The real "pointer const" will be int *const . You cannot assign any of this type here; but you can change the int it points to. Therefore, "const" for a pointer or reference is separate from "const" for what it points to. You can also have a "const pointer to const int": const int *const .

+1
source

My logic says the following: lambdas is just a piece of code with optional required links. In the case where you need to copy something (which usually happens for memory management purposes, for example, to copy shared_ptr), you still do not want the lambda to have its own state. This is a rather unusual situation.

I think that only the following two options seem to be "correct"

  • Close some code using some local variables so you can "pass it"
  • Same as above, just add memory management, because maybe you want to execute this part of the code asynchronously or something else and the creation area will disappear.

But when the lambda is "changeable", i.e. captures values ​​that are not constants, which means that it actually maintains its own state. Meaning, every time you call a lambda , it can give a different result, which is not based on its actual closure, but again, on its internal state, which is kind of counter-intuitive in my mind that lambdas come from functional languages .

However, C ++, which is C ++, gives you the ability to get around this limitation by also making it a little ugly, just to make sure you know that you are doing something weird.

I hope it will be with you.

0
source

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


All Articles