我有一个使用lambda表达式的函数。
std::vector<Bar*> mBars;
void foo(Bar* bar)
{
auto duplicateBars = std::remove_if(mBars.begin(), mBars.end(),
[bar] (const Bar* const &element)
{
return bar == element;
});
mBars.erase(duplicateBars, mBars.end());
}
后来,我查看了代码并意识到我可以为foo的签名添加两个consts。
void foo(const Bar* const bar);
bar
的指针和数据现在是常量,但是为了lambda表达式的目的,指针本身是常量,因为我按值捕获。但是,指向的数据可以更改,并且无法更改此数据,因为lambda捕获中不允许const
。
这对我来说不直观。我的解释是否正确?我可以使用第二个签名,但我无法保护数据不被lambda表达式更改。
答案 0 :(得分:7)
但是,指向的数据可以更改,并且无法更改此数据,因为lambda捕获中不允许使用const。
不,当在lambda表达式中捕获值时,保留constness,即捕获指向const
数据的指针将阻止更改lambda中的数据。
int i = 1;
const int* ptr = &i;
auto func = [ptr] {
++*ptr; // ERROR, ptr is pointer to const data.
}
当按值捕获时,lambda还会将顶级 constness添加到指针中(除非使用mutable
)。
auto func = [ptr] {
ptr = nullptr; // ERROR, ptr is const pointer (const int* const).
}
auto func = [ptr] () mutable { // Mutable, will not add top-level const.
ptr = nullptr; // OK
}
我可以使用第二个签名,但我无法保护数据不被lambda表达式更改。
您可以使用const
保护数据不被lambda内部更改。
const Bar* bar = &bar_data;
auto b = [bar] (const Bar* element) { // Data pointed to by bar is read-only.
return bar == element;
};
lambda表达式还将const Bar* const &
类型的参数,即 reference 引用到const数据的const指针。无需参考,只需选择const Bar*
。
有关指针和const
的更多信息:What is the difference between const int*, const int * const, and int const *?
答案 1 :(得分:2)
您的问题似乎源于对lambda表达式中变量捕获的工作原理的误解。通过复制捕获变量时,从lambda表达式生成的闭包类型中创建的相应数据成员将具有与原始对象相同的相同类型。这保留了const
- ness,你无法修改lambda体内的任何bar
点。
来自§5.1.2/ 15 [expr.prim.lambda]
如果隐式捕获并且 capture-default 为
=
或者使用捕获显式捕获实体,则捕获实体 不是& identifier
或& identifier initializer
的形式。对于由副本捕获的每个实体,在闭包类型中声明未命名的非静态数据成员。这些成员的声明顺序未指定。 此类数据成员的类型是相应的类型 如果实体不是对象的引用,则为捕获的实体,否则为引用的类型。