geza
geza

Reputation: 29970

Why does a variable refer to the variable outside of a lambda, if it is not odr used?

Look at this example (godbolt):

void foo(int &par) {
    auto l = [par]() {
        decltype(par) x;
    };
}

This program does not compile, because the par in decltype(par) refers to the parameter in foo, and not to the variable of the lambda (so decltype(par) is actually a reference type, which needs to be initialized).

Here is a relevant quote from the standard of C++14 (sorry about quoting an old standard, but I think it's easier to understand).

expr.prim.lambda/18 (emphasis is mine):

"Every id-expression within the compound-statement of a lambda-expression that is an odr-use of an entity captured by copy is transformed into an access to the corresponding unnamed data member of the closure type. [ Note: An id-expression that is not an odr-use refers to the original entity, never to a member of the closure type. Furthermore, such an id-expression does not cause the implicit capture of the entity. — end note ]"

And the standard makes sure that if decltype used on a non-id-expression, then even tough it doesn't odr-use the variable, the captured one is used (expr.prim.lambda/19):

"Every occurrence of decltype((x)) where x is a possibly parenthesized id-expression that names an entity of automatic storage duration is treated as if x were transformed into an access to a corresponding data member of the closure type that would have been declared if x were an odr-use of the denoted entity."

So, depending on these rules (and maybe the standard has other related rules), a variable in a lambda may refer to the captured one, or may refer to the original one in the enclosing function.

I have two questions:

  1. Why is it designed this way? Why not always use the captured variable? What does this extra complexity give us?
  2. How can I acquire the type of a captured variable inside a lambda?

(Note: a related previous question: What is the type of a by-value lambda capture of a reference?)

Upvotes: 11

Views: 243

Answers (1)

Öö Tiib
Öö Tiib

Reputation: 11011

  1. There are various ways to design with those dozen different explicit and implicit captures. Other ways may be similarly confusing or more wasteful. You are transforming a reference into copy with same name so it can happen to be confusing on its own.

  2. Can do by-copy capture with an initialiser:

    void foo(int &par) {
       auto l = [cap = par]() {
           decltype(cap) x; // no confusion about names
       };
    }
    

Upvotes: 1

Related Questions