Lambda's scope can implicitly capture variables within its reaching scope.
Your variables are in the reaching scope, since they are local to the (main) function that defines the lambda.
However, there are certain criteria in which variables can be captured via this mechanism, as mentioned in [expr.prim.lambda]/12:
A lambda-expression with an associated capture-default that does not
explicitly capture this or a variable with automatic storage duration
[..], is said to
implicitly capture the entity (i.e., this or a variable) if the
compound-statement:
-odr-uses ([basic.def.odr]) the entity, or
-names the entity in a potentially-evaluated expression ([basic.def.odr]) where the enclosing full-expression depends on a
generic lambda parameter declared within the reaching scope of the
lambda-expression.
The most important part is in [expr.const]/2.7:
A conditional-expression e
is a core constant expression unless the
evaluation of e
, [..] would evaluate one of the following expressions:
an lvalue-to-rvalue conversion ([conv.lval]) unless it is applied to:
a non-volatile glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization,
initialized with a constant expression.
So const int
is a core constant expression while const float
is not.
Moreover [expr.const]1826 mentions:
A const integer initialized with a constant can be used in constant expressions, but a const floating point variable initialized with a constant cannot.
Read more in Why is a const variable sometimes not required to be captured in a lambda?