16

Here is a piece of code that won't compile in MSVC 2015 (ignore the uninitialized value access):

#include <array>
int main() {
    constexpr int x = 5;
    auto func = []() {
        std::array<int, x> arr;
        return arr[0];
    };
    func();
}

It complains that:

'x' cannot be implicitly captured because no default capture mode has been specified

But x is a constexpr! x is known at compile time to be 5. Why does MSVC kick up a fuss about this? (Is it yet another MSVC bug?) GCC will happily compile it.

6

2 Answers 2

14

The code is well-formed. The rule from [expr.prim.lambda] is:

If a lambda-expression or an instantiation of the function call operator template of a generic lambda odr-uses (3.2) this or a variable with automatic storage duration from its reaching scope, that entity shall be captured by the lambda-expression.

Any variable that is odr-used must be captured. Is x odr-used in the lambda-expression? No, it is not. The rule from [basic.def.odr] is:

A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.20) that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression (Clause 5).

x is only used in a context where we apply the lvalue-to-rvalue conversion and end up with a constant expression, so it is not odr-used, so we do not need to capture it. The program is fine. This is the same idea as why this example from the standard is well-formed:

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
    };
    // ...
}
Sign up to request clarification or add additional context in comments.

Comments

-2

Even though x is a constexpr, it is no different from any other object, otherwise, and follows the same rules with regards to scoping. There are no exceptions to scoping rules for constexprs, and a lambda must be coded to explicitly capture it.

8 Comments

Is there then a way to capture it but allow me to use it as a template parameter as in my code?
That's another question.
clang would allow you to just capture it [x]() {...} and then use it as a template parameter, yet GCC doesn't. I'm confused.
@Bernard just make it static, no need to capture.
No, this isn't the case, -1.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.