Can a Lambda Capturing Nothing Access Global Variables

Can a lambda capturing nothing access global variables?

Yes, sure. Normal name lookup rules apply.

[expr.prim.lambda]/7 ... for purposes of name lookup ... the compound-statement is considered in the context of the lambda-expression.

Re: why local variables are treated differently from global ones.

[expr.prim.lambda]/13 ... If a lambda-expression or an instantiation of the function call operator template of a generic lambda odr-uses (3.2) this or a variable with automatic storage duration from its reaching scope, that entity shall be captured by the lambda-expression.

[expr.prim.lambda]/9 A lambda-expression whose smallest enclosing scope is a block scope (3.3.3) is a local lambda expression... The reaching scope of a local lambda expression is the set of enclosing scopes up to and including the innermost enclosing function and its parameters.

In your example, m is a variable with automatic storage duration from the lambda's reaching scope, and so shall be captured. n is not, and so doesn't have to be.

How can I access of a variable inside a lambda without using a global variable?

Use lambda with capture. Notice the [&].

Here is a demo.

#include <iostream>
using namespace std;

int main() {
int k=0;int n=0;

auto func1=[=]()mutable{k=1;n=1;}; //capture k by value
func1();
std::cout<<k<<std::endl; //print 0

auto func2=[&](){k=2;n=1;}; //capture k by reference
func2();
std::cout<<k<<std::endl; //print 2 (k changed)

auto func3=[k]()mutable{k=3;/* n=1; compile fail*/}; //capture k by value
func3();
std::cout<<k<<std::endl; //print 2

auto func4=[&k](){k=4; /* n=1; compile fail*/}; //capture k by reference
func4();
std::cout<<k<<std::endl; //print 4 (k changed)
}

More about mutable : Why does C++0x's lambda require "mutable" keyword for capture-by-value, by default?

GCC incorrectly captures global variables by reference in lambda functions?

§5.1.2/11:

If a *lambda-expression( has an associated capture-default and its compound-statement odr-uses (3.2) this or a variable with automatic storage duration and the odr-used entity is not explicitly captured, then the odr-used entity is said to be implicitly captured; ...

Global variables have static storage duration (§3.7.1), so the global a will not be implicitly captured by value. Still, you can access a global variable anywhere, so

[=]() { a = 9; } ();

will set the global a to 9 as expected.

Explicitly capturing a global should be an error or UB, because §5.1.2/10 says

The identifiers in a capture-list are looked up using the usual rules for unqualified name lookup (3.4.1); each such lookup shall find a variable with automatic storage duration declared in the reaching scope of the local lambda expression.

using out of scope variables in C++11 lambda expressions

You need to capture the variable, either by value (using the [=] syntax)

bool repeated = std::any_of(agents.begin(), agents.end(),
[=](P_EndPoint i)->bool
{return requestPacket.identity().id()==i.id();});

or by reference (using the [&] syntax)

bool repeated = std::any_of(agents.begin(), agents.end(),
[&](P_EndPoint i)->bool
{return requestPacket.identity().id()==i.id();});

Note that as @aschepler points out, global variables with static storage duration are not captured, only function-level variables:

#include <iostream>

auto const global = 0;

int main()
{
auto const local = 0;

auto lam1 = [](){ return global; }; // global is always seen
auto lam2 = [&](){ return local; }; // need to capture local

std::cout << lam1() << "\n";
std::cout << lam2() << "\n";
}

lambda function accessing outside variable

You can "capture" the i when creating the lambda

lambda x, i=i: x%i==0

This will set the i in the lambda's context equal to whatever i was when it was created. you could also say lambda x, n=i: x%n==0 if you wanted. It's not exactly capture, but it gets you what you need.


It's an issue of lookup that's analogous to the following with defined functions:

glob = "original"

def print_glob():
print(glob) # prints "changed" when called below

def print_param(param=glob): # default set at function creation, not call
print(param) # prints "original" when called below

glob = "changed"
print_glob()
print_param()

Why is my global, extern lambda variable not initialized at runtime?

The problem had to do with static initialization order. Since the lambdas often relied on each other already being initialized in a specific order, the initialization would not happen and the global lambdas would be left in an invalid state, thus causing the std::bad_function_call exceptions at runtime.

To fix the problem, I moved the initialization of the global lambda variables to runtime.

How can I disable implicit lamba variable capture?

The only "implicit capture" happens with the static and global variables in the scope. And there's no way to get rid of this.

Why capture lambda does not working in c++?

auto kitten = [=] () {return g+1;}

This lambda doesn't capture anything at all. It's nearly the same as just

int kitten() { return g+1; }

Only local variables can be captured, and there are no local variables visible in the scope of the kitten definition. Note that [=] or [&] don't mean "capture everything", they mean "capture anything necessary", and a global variable is never necessary (or possible) to capture in a lambda, since the meaning of that variable name is always the same no matter when the lambda body is evaluated.



auto cat = [g=g] () {return g+1;}

Here's an init-capture, which is similar to creating a local variable and immediately capturing it. The g before the equal sign declares the init-capture, and the g after the equal sign specifies how to initialize it. Unlike most declarators (see below), the g variable created here is not in scope in its own initializer, so the g after the equal sign means the global variable ::g. So the code is similar to:

auto make_cat()
{
int & g = ::g;
return [g]() { return g+1; }
}
auto cat = make_cat();


auto kitten = [] () {int g  = g; return g+1;}

This code has a mistake not really related to lambdas. In the local variable definition int g = g;, the declared variable before the equal sign is in scope during the initializer after the equal sign. So g is initialized with its own indeterminate value. Adding one to that indeterminate value is undefined behavior, so the result is not predictable.

How can I access a non-final variable in a Thread lambda?

Suppose this was allowed? What would you expect it to return?

// Warning! This is an example of what *NOT* to do.
//
public Response get(String endpoint) {
Response response = new Response();
new Thread(() -> {
response = OffredUtil.makeGetRequest(endpoint);
}).start();
return response;
}

There's no reason to think that response = OffredUtil.makeGetRequest(endpoint); statement will be executed until before the return response; statement. In fact, it probably will not be executed until some time later.

What you really want is;

  • for your get(endpoint) method to return a mutable object, and
  • a way for a caller to wait until a new value has been stored into the mutable object by some other thread.

The Java standard library defines an interface for just that kind of mutable object: It's called java.util.concurrent.Future. A Future has a get() method that will wait, if necessary, until some other thread has completed the Future by giving it a value, and then the get() will return the value.

The simplest way to use it is through the CompletableFuture class:

import java.util.concurrent.Future;
import java.util.concurrent.CompletableFuture;
...
public Future<Response> get(String endpoint) {
return CompletableFuture.supplyAsync(() -> {
return OffredUtil.makeGetRequest(endpoint);
});
}

A call to this get(endpoint) method will submit a task to a built-in thread pool that will execute the given lambda expression, and then it will return a Future that will be completed by the task.

If the lambda produces a value, then that will become the value of the Future. If the lambda throws an exception, then that will be caught and, and the exception object will be stored in the Future

The caller of get(endpoint) can do this:

...
Future<Response> fr = myClassInstance.get(endpoint);
doSomethingElseConcurrentlyWithThe_makeGetRequest_call(...);
try {
Response r = fr.get();
...
} catch (Exception e) {
o.response.isException = true;
Log.d(TAG, e.getMessage());
}

How does lambda capture local static variable?

You don't need to capture global or static variables. Only automatic variables have to be captured if you want to use them.

Because of that, yes, you can convert such lambda to a function pointer.


Cppreference:

The identifier in any capture without an initializer (other than the this-capture) is looked up using usual unqualified name lookup in the reaching scope of the lambda. The result of the lookup must be a variable with automatic storage duration declared in the reaching scope.

(emphasis mine)

"To capture" means to put a copy or a reference to a variable into a lambda object itself.

Global and static variables have fixed memory location. You don't need to store copies or references to them to use them since their location is known at compile time and doesn't change.

(If you really want to have a copy of a global or static variable, you can create it using named capture from C++14, which lets you create a custom member variable in a lambda object. But such capture is not necessary if you just want to use that global / static variable.)

Automatic variables, on the other hand, don't have a fixed location. Multiple lambdas created at the exact same place could refer to different automatic variables. Because of that, a lambda object has to capture such variable - which means to contain either a reference to used automatic variable or a copy of it.



Related Topics



Leave a reply



Submit