必须在C++中用lambda捕获constexpr表达式吗?

Ber*_*ard 11 c++ lambda visual-c++ constexpr c++14

这是一段无法在MSVC 2015中编译的代码(忽略未初始化的值访问):

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

它抱怨说:

'x' cannot be implicitly captured because no default capture mode has been specified
Run Code Online (Sandbox Code Playgroud)

但是x是一个constexpr! x在编译时是已知的5.为什么MSVC会对此大做文章?(是不是另一个MSVC的错误?)GCC将愉快地编译它.

Bar*_*rry 8

代码格式正确.[expr.prim.lambda]的规则是:

如果lambda表达式或函数的实例化调用一般lambda odr使用的操作符模板(3.2)this或具有自其存储持续时间的变量,则该实体应由lambda表达式捕获.

必须捕获任何使用odr的变量.是否x在lambda表达式中使用了odr?不它不是.[basic.def.odr]的规则是:

除非应用左值到右值转换(4.1)以产生不调用任何非平凡函数的常量表达式(5.20),否则x其名称显示为可能已评估的表达式的变量将被ex使用.如果是object,是表达式的潜在结果集合的元素,其中左值到右值的转换(4.1)应用于或者是丢弃值表达式(第5节).exxxexeee

x仅在我们应用左值到右值转换并最终得到常量表达式的上下文中使用,因此它不会被使用,因此我们不需要捕获它.该计划很好.这与为什么标准中的这个例子格式正确的想法是一样的:

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
    };
    // ...
}
Run Code Online (Sandbox Code Playgroud)