常量λ是什么意思

What does const lambda mean?

本文关键字:意思 是什么 常量      更新时间:2023-10-16
#include <iostream>
int foo(int i)
{
    const auto a = [&i](){ i = 7; };
    a();
    return i;
}
int main()
{
    std::cout << foo(42) << std::endl;
    return 0;
}

这将编译(g++ -std=c++11 -Wall -Wextra -Wpedantic main.cpp(并打印7。这让我感到惊讶,因为通过将a声明为常量对象,我本来希望i被引用为const int&。显然不是,为什么?

Lambda 就像非 lambda 一样,只是它们的实现细节是隐藏的。因此,使用非 lambda 函子可能更容易解释:

#include <iostream>
int foo(int i)
{
    struct F {
      int &i;
      int operator()() const { i = 7; return i * i; }
    };
    const F a {i};
    a();
    return i;
}
int main()
{
    std::cout << foo(42) << std::endl;
    return 0;
}

F有一个int &引用成员iconst F不能修改其实例数据,但对i的修改不是对其实例数据的修改。对其实例数据的修改将重新绑定i到另一个对象(无论如何都不允许这样做(。

[&i](){ i = 7; return i * i; }

主要相当于

class Lambda
{
public:
    Lambda(int& arg_i) : i(arg_i) {}
    auto operator() () const { i = 7; return i * i;}
private:
    int& i;
};

因此,您就有了:

const Lambda a(i);
a();

而且const Lambda不会将其成员提升const int& i;而是int& const i;,这相当于int& i;

当你i时,它被捕获为它的类型。

所以在内部它有一个int&.闭包的变量声明之前的 const 不会更改 lambda 的任何内容。

您有 2 个选项可以解决此问题:

const int i = 5;
auto b = [&i]() { i++; }; //error on i++

这样,将捕获const int&

如果由于某些原因无法更改i则可以在 c++14 中执行此操作

int i = 5;
auto b = [i = static_cast<const int&>(i)]() { i++; }; //error on i++

这会将int&转换为const int&,并将以这种方式存储在 lambda 中。虽然如您所见,这更加冗长。

在您给出的代码中:

int foo(int i)
{
    const auto a = [&i](){ i = 7; return i * i; };
    a();
    return i;
}
初始化

常量 lambda 函数后,您不会进行分配。因此,在这种情况下,const意义不大。

你声明的const它不是你的匿名函数或lambda压榨及其参数的上下文,而只是对该lambda表达式的引用:const auto a

因此,您无法更改 lambda expr 引用的值a因为它是 const 的,但其通过引用传递的参数 &i 可以在 lambda 表达式的上下文中更改。

如果我

理解正确的话,问题是为什么你可以改变i,即使aconst并且可能包含对i作为成员的引用。

答案是,出于同样的原因,您可以在任何对象上执行此操作 - 分配给 i 不会修改 lambda 实例,而是修改它引用的对象。

例:

class A
{
public:
    A(int& y) : x(y) {} 
    void foo(int a) const { x = a; } // But it's const?!
private:
    int& x;
};
int main()
{
    int e = 0;
    const A a(e);
    a.foo(99);
    std::cout << e << std::endl;
}

这将编译并打印"99",因为foo不是在修改a的成员,而是在修改e
(这有点令人困惑,但它有助于思考哪些对象正在被修改,而忽略它们的命名方式。

const的这种"恒定,但不是真的"性质是混乱和烦恼的一个非常常见的来源。

这正是指针的行为方式,更显然没有错:

class A
{
public:
    A(int* y) : x(y) {} 
    void foo(int a) const { *x = a; } // Doesn't modify x, only *x (which isn't const).
private:
    int* x;
};