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

时间:2017-03-05 15:49:31

标签: c++ visual-c++ lambda c++14 constexpr

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

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

它抱怨说:

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

xconstexprx在编译时称为5。为什么MSVC会对此大做文章? (另一个MSVC错误?)GCC很乐意编译它。

2 个答案:

答案 0 :(得分:8)

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

  

如果 lambda-expression 或函数的实例化调用泛型lambda odr的运算符模板 - 使用(3.2)this或变量   自达到范围的自动存储持续时间,该实体应由 lambda-expression 捕获。

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

  

x的名称显示为可能评估的表达式ex的变量exx使用,除非将左值到右值的转换(4.1)应用于{{1产生一个不调用任何非平凡的常量表达式(5.20)   函数,如果x是一个对象,ex是表达式e的潜在结果集合的元素,其中应用了左值到右值的转换(4.1)到e,或e是丢弃值表达式(第5条)。

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
    };
    // ...
}

答案 1 :(得分:0)

即使xconstexpr,它也与任何其他对象没有区别,否则,遵循与范围有关的相同规则。 constexpr的范围规则没有例外,必须对lambda进行编码以明确捕获它。