c++ const lambda是什么意思

f1tvaqid  于 2023-05-20  发布在  其他
关注(0)|答案(6)|浏览(133)
#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&。显然不是,为什么?

3gtaxfhh

3gtaxfhh1#

Lambdas就像非Lambdas一样,除了它们的实现细节是隐藏的。因此,使用非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重新绑定到另一个对象(这无论如何都是不允许的)。

plupiseo

plupiseo2#

[&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;

8yoxcaq7

8yoxcaq73#

当你捕获i时,它被捕获为它的类型。
所以它内部有一个int&。闭包的变量声明前的const不会改变lambda的任何内容。
你有两个选择来解决这个问题:

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中。虽然这是更详细的方式,因为你可以看到。

uurv41yg

uurv41yg4#

在您提供的代码中:

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

在初始化常量lambda函数后,您没有进行赋值。因此,const在此上下文中没有太大意义。

lymnna71

lymnna715#

你声明为const的内容不是匿名函数或lambda表达式及其参数的上下文,而只是lambda表达式的引用:const auto a
因此,您不能更改lambda expr引用a的值,因为它是const,但其通过引用传递的参数&i可以在lambda表达式的上下文中更改。

yjghlzjz

yjghlzjz6#

如果我理解正确的话,问题是为什么允许你改变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
(This有点令人困惑,但它有助于思考哪些 * 对象 * 正在被修改,而忽略它们的命名方式。)
const的这种“const,but not really”性质是非常常见的混淆和烦恼的来源。
这正是指针的行为方式,更明显的是它没有错:

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

相关问题