Title
Constant expressions and lambda capture
Status
c++14
Section
7.5.5.3 [expr.prim.lambda.capture]
Submitter
Michael Wong

Created on 2013-01-31.00:00:00 last changed 92 months ago

Messages

Date: 2014-02-15.00:00:00

[Moved to DR at the February, 2014 meeting.]

Date: 2013-09-15.00:00:00

Proposed resolution (September, 2013):

Add the following bullet to 7.7 [expr.const] paragraph 2:

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (6.9.1 [intro.execution]), would evaluate one of the following expressions:

  • ...

  • in a lambda-expression, a reference to this or to a variable with automatic storage duration defined outside that lambda-expression, where the reference would be an odr-use (6.3 [term.odr.use], 7.5.5 [expr.prim.lambda]);

  • a conversion from type cv void * to a pointer-to-object type;

  • ...

Date: 2014-05-27.00:00:00
N3690 comment CA 16

Since instances of a variable in constant expressions may be odr-uses, the ordering of:

  • constant expression evaluation,

  • the determination of implicit captures, and

  • the transformation to use closure members for odr-uses of captured variables

may affect the semantics of a program such as the one below.

The transformation under 7.5.5 [expr.prim.lambda] paragraph 17 introduces uses of the this pointer of the operator() in its function-body. These instances of this are invalid under issue 1369 if the transformation is applied before the evaluation of the constant expressions. Without the resolution of issue 1369, another situation occurs where instances of this in the compound-statement are transformed into class member access expressions (see the initializations of addrEqA and addrEqB below).

Also, for the initialization of nonZero below, the expression fails to be a constant expression if the transformation is applied before constant expression evaluation.

Finally, the answer to the static assertion changes depending on whether the constant expression evaluation is performed before the transformation as opposed to after and whether the proposed resolution issue 1472 is enabled.

There appears to be implementation divergence regarding

  • whether the lexical instances of this in the initialization of addrEqB is valid and

  • whether the static assertion should pass.

Using explicit value captures is not a panacea, since the paragraph 17 transformations only apply to odr-uses. As a result of the resolution of issue 1472, if the reference r below happened to have been initialized with a constant expression, the value of its (modifiable) target is not captured; if the same target were specified in the initialization of the reference with a non-constant expression, its value would be captured.

  struct A {
    void foo();
  };

  struct LitType { int val; };
  constexpr int ceFunc(const LitType &x) { return x.val; }

  void A::foo() {
    constexpr LitType y = { 0 };
    static int z;
    int x, &r = z;
    [=] {
     constexpr bool addrEqA = &x == &x;         // ill-formed under issue 1369 after transformation
                                                // under paragraph 17
     constexpr bool addrEqB = &*this == &*this; // well-formed after transformation under N3290
                                                // paragraph 17
     constexpr bool nonZero = ceFunc(y);        // lvalue-to-rvalue conversion occurs only after
                                                // function invocation substitution; the closure member,
                                                // being not a variable, cannot be constexpr
     static_assert(&r != &z,
       "reference which could be captured by value found to alias target");
                                                // affected by issue 1472
    };
  }
History
Date User Action Args
2014-11-24 00:00:00adminsetstatus: dr -> c++14
2014-03-03 00:00:00adminsetmessages: + msg4937
2014-03-03 00:00:00adminsetstatus: ready -> dr
2013-10-14 00:00:00adminsetmessages: + msg4574
2013-10-14 00:00:00adminsetstatus: drafting -> ready
2013-05-03 00:00:00adminsetstatus: open -> drafting
2013-01-31 00:00:00admincreate