为什么值为值的值为const,而不是按引用对象捕获:
int a;
auto compile_error = [=]()
{
a = 1;
}
auto compiles_ok = [&]()
{
a = 1;
}
对我而言,这似乎不合逻辑,但它似乎是标准的?特别是因为对捕获值的不必要修改可能是一个烦人的错误,但是后果仅限于lambda范围的可能性很高,而通过引用捕获的对象的不需要的修改通常会导致更严重的影响。
那么为什么不默认使用const引用?或者至少支持[const&]和[&]?这种设计的原因是什么?
作为解决方法,您可能应该使用由值捕获的std :: cref包装的const引用吗?
答案 0 :(得分:7)
假设您正在按值捕获指针。指针本身是const,但是对它指向的对象的访问不是。
int i = 0;
int* p = &i;
auto l = [=]{ ++*p; };
l();
std::cout << i << std::endl; // outputs 1
这个lambda相当于:
struct lambda {
int* p;
lambda(int* p_) : p(p_) {}
void operator()() const { ++*p; }
};
const
上的operator()()
使用p
相当于将其声明为:
int* const p;
引用也会发生类似的事情。引用本身是“const”(在引号中,因为引用不能重新引用),但是引用它引用的对象不是。
答案 1 :(得分:2)
捕获的引用 也是const
。或者更确切地说,引用总是隐式地const
- 语言中没有语法允许您更改引用所指向的位置。当a = 1;
是引用时,a
不会更改引用,而是更改引用所引用的内容。
当你谈到“const reference”时,我觉得你很困惑。您正在谈论“引用const int”(const int &
)。 “const”指的是引用指向的东西,而不是引用本身。它与指针类似:使用“指向const int的指针”(const int *
),指针本身不是const
- 您可以根据需要分配给此类型的变量。一个真正的“const指针”将是int *const
。在这里,你不能分配这种类型的东西;但你可以修改它指向的int
。因此,指针或引用的“const”与它指向的东西的“const”是分开的。您还可以使用“const指向const int的指针”:const int *const
。
答案 2 :(得分:0)
我的逻辑说明如下:lambdas只是一段代码,带有可选的必需引用。在您需要实际复制某些内容(通常用于内存管理目的,例如复制shared_ptr)的情况下,您仍然不希望lambda具有自己的状态。这是一个非常不寻常的情况。
我认为只有以下2个选项感觉“正确”
但是当lambda是“可变的”时,即它捕获的值不是const,这意味着它实际上支持它自己的状态。这意味着,每次调用 lambda 时,它都会产生不同的结果,这不是基于其实际的闭包,而是基于其内部状态,这在我的书中有点反直觉,因为lambda起源于函数式语言。
然而,C ++,作为C ++,为你提供了一种绕过这种限制的方法,也让它变得有点丑陋,只是为了确保你知道你做了一些奇怪的事情。
我希望你有这个理由。