具有空捕获的Lambda表达式

时间:2017-03-30 13:40:22

标签: c++ c++11 lambda language-lawyer

我在使用lambdas时遇到过一个有趣的案例(至少对我来说),并且想知道它是编译器错误还是标准功能允许的内容。

让我们切入追逐。有示例代码:

const int controlValue = 5;
std::vector<int> vect{ 0, 1, 2, 3 };
const auto result = std::any_of(vect.begin(), vect.end(), [](const int& item)
{
    return item == controlValue;
});

请注意,lambda表达式未捕获controlValue变量。 此外,在lambda表达式的cppreference中,声明[] - captures nothing

使用 VS2015 编译上述代码会出现错误并不奇怪:

error C3493: 'controlValue' cannot be implicitly captured because no default capture mode has been specified

然而,当 MinGW gcc 4.8.2 一起使用时,相同的例子编译并运行。 一些在线编译器包括 gcc 5.4.0 clang 3.8.0 给出了类似的结果。

controlValue丢失其const时,所有经过测试的编译器都会给出所有期望的错误(没有捕获该变量,这很好)。

在这种情况下,哪些编译器符合标准? 这是否意味着某些优化或其他“黑客”在这里用于const变量?也许某些内容是隐含的? 谁能解释一下这里发生的情况呢?

修改

有人指出这个问题与Lambda capturing constexpr object 重复。虽然答案可能有些相关(指向odr用例),但是有关在通过ref捕获时发生错误的问题。这里的主题是完全不同的,并侧重于根本不捕获显式变量(尽管在lambda体中使用它)。

在查看了更多与lambda相关的问题后,如果有人感兴趣,我会指向Using lambda captured constexpr value as an array dimension (与@Barry说的相同)建议VS2015错误并显示在示例中设置controlValue变量这里static修复了VS2015下的编译。

1 个答案:

答案 0 :(得分:16)

这是一个VS错误。代码完美无缺。

[expr.prim.lambda]中的规则是:

  

如果lambda表达式或函数的实例化调用一般lambda odr的运算符模板(3.2)这个或具有自动存储持续时间的变量到达范围,该实体应被lambda表达式捕获。

根据[basic.def.odr]:

,如果变量是odr使用的话
  

变量x的名称显示为可能评估的表达式ex,除了将lvalue-to-rvalue转换(4.1)应用于x得到常量表达式(5.20)之外,ex 使用odr这不会引起任何重要的琐事   函数和,如果x是一个对象,ex是表达式e的潜在结果集的一个元素,其中将左值到右值的转换(4.1)应用于e ,或者e是一个废弃值表达式(第5条)。

并且,来自[expr.const]:

  

条件表达式e是核心常量表达式,除非e的评估遵循规则   抽象机器(1.9),将评估以下表达式之一:[...]左值到右值的转换(4.1),除非它应用于整数或枚举类型的非易失性glvalue,指的是完全非具有前面初始化的易失性const对象,用常量表达式初始化

在:

return item == controlValue;

controlValue是整数类型的glvalue,它指的是用常量表达式初始化的完整的非易失性const对象。因此,当我们在涉及左值到右值转换的上下文中使用controlValue时,它不会被使用。由于它没有使用,我们不需要捕获它。

当您将controlValue更改为 - const时,它将不再是常量表达式,并且相等检查odr-使用它。由于它没有被捕获但是被使用了,因此lambda是不正确的。

请注意,标准中出现了这样的示例:

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

    // ...
}