Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I access local variables from inside a C++11 anonymous function?

I'm doing a simple normalization on a vector (weights), trying to make use of STL algorithms to make the code as clean as possible (I realize this is pretty trivial with for loops):

float tot = std::accumulate(weights.begin(), weights.end(), 0.0);
std::transform(weights.begin(), weights.end(), [](float x)->float{return(x/tot);});

At present, tot is not visible to the anonymous function, so this doesn't compile. What's the best way of making a local variable visible to the anonymous function?

like image 659
bd1 Avatar asked Aug 17 '11 23:08

bd1


People also ask

Can I access a local variable in another function?

No you can't, that's what "local" means. Besides that, you don't define a variable of any kind named my_reply anywhere in your code. in the sample code , I have a my function , in my function I am assigning reply to global variable . When I print global variable in my function i.e t .

How do you capture variables in lambda?

Capture clause A lambda can introduce new variables in its body (in C++14), and it can also access, or capture, variables from the surrounding scope. A lambda begins with the capture clause. It specifies which variables are captured, and whether the capture is by value or by reference.

How local variables can be accessed?

The local variable can be accessed by using the object of the Demo class, whereas the static variable can be accessed using the name of the class.

How do you capture a variable in lambda C++?

Much like functions can change the value of arguments passed by reference, we can also capture variables by reference to allow our lambda to affect the value of the argument. To capture a variable by reference, we prepend an ampersand ( & ) to the variable name in the capture.


3 Answers

You need a closure.

float tot = std::accumulate(weights.begin(), weights.end(), 0); std::transform(weights.begin(), weights.end(), [tot](float x)->float{return(x/tot);}); 

In this case tot is captured by value. C++11 lambdas support capturing by:

  1. value [x]
  2. reference [&x]
  3. any variable currently in scope by reference [&]
  4. same as 3, but by value [=]

You can mix any of the above in a comma separated list [x, &y].

like image 123
pmr Avatar answered Oct 16 '22 02:10

pmr


The lambda can "capture" variables from the ambient scope:

[ ..., N, ... ](int a, int b) -> int  { return (a + b) * N; }
 ^^^^^^^^^^^^^  ^^^^^^^^^^^^     ^^^^
 captured vars  local params     ret.type

You can capture by value or by reference, and you can use the special syntax [=] and [&] to capture anything from the ambient scope, i.e. anything you actually end up using.

like image 24
Kerrek SB Avatar answered Oct 16 '22 02:10

Kerrek SB


You need to add tot to the "capture list":

float tot = std::accumulate(weights.begin(), weights.end(), 0);
std::transform(weights.begin(), weights.end(), [tot](float x)->float{return(x/tot);});

Alternatively you can use a capture-default to capture tot implicitly:

float tot = std::accumulate(weights.begin(), weights.end(), 0);
std::transform(weights.begin(), weights.end(), [=](float x)->float{return(x/tot);});
like image 27
Mankarse Avatar answered Oct 16 '22 00:10

Mankarse