const lambda是什么意思?

时间:2016-10-14 11:36:18

标签: c++ c++11 lambda const

#include <iostream>
int foo(int i)
{
    const auto a = [&i](){ i = 7; return i * i; };
    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&。这显然不是,为什么?

6 个答案:

答案 0 :(得分:6)

Lambda就像非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到另一个对象(无论如何都不允许)。

答案 1 :(得分:6)

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

答案 2 :(得分:5)

当你捕获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中。虽然你可以看到这种方式更加冗长。

答案 3 :(得分:2)

在您提供的代码中:

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

初始化常量lambda函数后,您没有进行赋值。因此,const在这种情况下意义不大。

答案 4 :(得分:0)

如果我理解正确,那么问题就是为什么即使ia并且可能包含const作为成员的引用,也允许您变异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;
};

答案 5 :(得分:0)

您声明为const的内容它不是您的匿名函数或lambda exspression及其参数的上下文,而只是该lambda表达式的引用:const auto a

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