【问题标题】:Must constexpr expressions be captured by a lambda in C++?constexpr 表达式必须由 C++ 中的 lambda 捕获吗?
【发布时间】:2017-07-25 10:13:16
【问题描述】:

这是一段在 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 会很高兴地编译它。

【问题讨论】:

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


【解决方案1】:

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

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

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

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

x 仅在我们应用左值到右值转换并以常量表达式结束的上下文中使用,因此它不是 odr 使用的,因此我们不需要捕获它。程序很好。这与为什么标准中的这个示例格式正确的想法相同:

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

【讨论】:

    【解决方案2】:

    尽管xconstexpr,但它与任何其他对象没有什么不同,除此之外,在作用域方面遵循相同的规则。 constexprs 的范围规则没有例外,必须对 lambda 进行编码才能显式捕获它。

    【讨论】:

    • 有没有办法捕获它,但允许我像在我的代码中一样将它用作模板参数?
    • 那是另一个问题。
    • clang 将允许您捕获它[x]() {...},然后将其用作模板参数,但 GCC 不会。我很困惑。
    • @Bernard 把它改成static,不需要捕获。
    • 不,不是这样,-1。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-04
    • 2015-11-23
    相关资源
    最近更新 更多