Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the deduction rules for automatic argument capture?

I saw the equivalent of this code earlier, and I was a little surprised to learn that it worked as intended:

#include <iostream>

int main() 
{
    int a = 10;
    [=]() mutable {
        [&]() {
            a += 10;
            std::cout << "nested lambda: a=" << a << std::endl;
        }(); // call nested lambda
    }(); // call first lambda
    std::cout << "a=" << a << std::endl;
}

As was desired, the output is

nested lambda: a=20
a=10

I was surprised that the compiler figures out that a is used in the nested lambda, and correctly captures it by value in the first lambda even though it is not explicitly used there. I.e., the compiler must make the connection between the a in the nested lambda, and a in the outer scope. I thought that the argument capture would need to be explicit (i.e. [a] in the first lambda, [&a] in the nested), for it to work.

What are the deduction rules for automatic argument capture?

like image 755
pingul Avatar asked Aug 09 '18 04:08

pingul


1 Answers

This is described in [expr.prim.lambda.capture]p7:

For the purposes of lambda capture, an expression potentially references local entities as follows:

  • An id-expression that names a local entity potentially references that entity; an id-expression that names one or more non-static class members and does not form a pointer to member ([expr.unary.op]) potentially references *this.

  • A this expression potentially references *this.

  • A lambda-expression potentially references the local entities named by its simple-captures.

If an expression potentially references a local entity within a declarative region in which it is odr-usable, and the expression would be potentially evaluated if the effect of any enclosing typeid expressions ([expr.typeid]) were ignored, the entity is said to be implicitly captured by each intervening lambda-expression with an associated capture-default that does not explicitly capture it.

In other words:

A lambda implicitly captures under the following circumstances if the usage requires a definition, typeid expressions are ignored, and they are not explicitly captured:

  • a variable is named; or if the name of a non-static class member (not counting pointer to members) appears, then *this is implicitly captured, or

  • this appears, then *this is implicitly captured

The implicitly captured entities are implicitly captured by each intervening lambda with a default capture.

like image 103
Rakete1111 Avatar answered Nov 03 '22 22:11

Rakete1111