4

I can not quite understand an example from C++14 standard draft N4140 5.1.2.12 [expr.prim.lambda].

A lambda-expression with an associated capture-default that does not explicitly capture this or a variable with automatic storage duration (this excludes any id-expression that has been found to refer to an initcapture’s associated non-static data member), is said to implicitly capture the entity (i.e., this or a variable) if the compound-statement:

  • odr-uses the entity, or
  • names the entity in a potentially-evaluated expression where the enclosing full-expression depends on a generic lambda parameter declared within the reaching scope of the lambda-expression.

[ Example:

void f(int, const int (&)[2] = {}) { } // #1
void f(const int&, const int (&)[1]) { } // #2
void test() {
  const int x = 17;
  auto g = [](auto a) {
    f(x); // OK: calls #1, does not capture x
  };
  auto g2 = [=](auto a) {
    int selector[sizeof(a) == 1 ? 1 : 2]{};
    f(x, selector); // OK: is a dependent expression, so captures x
  };
}

—end example ]

All such implicitly captured entities shall be declared within the reaching scope of the lambda expression.

[ Note: The implicit capture of an entity by a nested lambda-expression can cause its implicit capture by the containing lambda-expression (see below). Implicit odr-uses of this can result in implicit capture. —end note ]

I thought that the beginning of a phrase a lambda-expression with an associated capture-default should prohibit any implicit capture (and it's confirmed by comment), therefore #1 call will lead to an error (something about using not captured variable). So how it works? What will be first argument of f? What if g will be called after exiting test() scope? What if I change #1 signature to void(const int&)?

--

upd: Thanks to all for explanation of how it works. Later I'll try to find and post references to standard about this case.

magras
  • 1,709
  • 21
  • 32

1 Answers1

0

As T.C. said in his comment, #1 does not require a capture as x is known at compile time and is therefore baked into the lambda. Not unlike how the function f is known at compile time so it doesn't need to be captured.

I believe if you change f's signature to int const & you are now attempting to pass the address of the constant which is on the stack, thus subject to changes, and it would require capturing x by value or reference.

nate
  • 1,771
  • 12
  • 17