Home > Software engineering >  From what part of the standard should I understand I can use a constexpr local variable in a if cons
From what part of the standard should I understand I can use a constexpr local variable in a if cons

Time:09-01

This compiles

void f() {
    constexpr bool x{};
    auto g = []{
        if constexpr (x) {
        }
    };
    g();
}

int main () {
    f();
}

and it compiles even if I change [] to [x] or to [&x]. In these two latter cases, though, clangd tells me

Lambda capture 'x' is not required to be captured for this use (fix available) [-Wunused-lambda-capture]

A first minor question would be: is capturing x in this case simply redundant? Or there's more?

But my main question is: from where in the standard should I understand that I can make without any capture in the case above? After all, just writing (void)x; before the if constexpr, for instance, makes the capture ([x] or [&x]) necessary.

CodePudding user response:

A variable is required to be captured if it is a local entity that is odr-used within the lambda expression. See [basic.def.odr]/10. In your example, x is a local entity but it is not odr-used by if constexpr (x) because:

  • x is a variable of non-reference type that is usable in constant expressions and has no mutable subobjects, and
  • the lvalue-to-rvalue conversion is applied immediately.

See [basic.def.odr]/5.2. (In a limited set of situations, the lvalue-to-rvalue conversion is allowed to not be done immediately; see [basic.def.odr]/3.)

In general, [basic.def.odr]/5 is the place to look when you need to determine whether a variable is odr-used.

CodePudding user response:

The case is ODR-usage (or rather: non-ODR-usage in this particular case) and it's not C 20-specific.

See expr.prim.lambda.capture

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 (7.6.1.7) 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.

Taking a look into the examples and notes that follow may also be worthwhile:

Note: The set of captured entities is determined syntactically, and entities might be implicitly captured even if the expression denoting a local entity is within a discarded statement (8.5.1). Example:

template<bool B>
void f(int n) {
  [=](auto a) {
    if constexpr (B && sizeof(a) > 4) {
      (void)n; // captures n regardless of the value of B and sizeof(int)
    }
  }(0);
}

In previous standards it was more clearly stated imho, see: https://stackoverflow.com/a/42611583/4885321

  • Related