何时解析 C++11 lambda 表达式中的变量引用
When is a variable reference in a C++11 lambda expression resolved?
我有一个(希望)关于lambda表达式的简单问题:
#include <vector>
#include <algorithm>
//----------------------------------------------------------------
void DoSomething()
//----------------------------------------------------------------
{
std::vector<int> elements;
elements.push_back(1);
elements.push_back(2);
int ref = 1;
auto printhit = [=](int iSomeNumber)
{
if (ref == iSomeNumber)
{
printf("Hit: %dn", iSomeNumber);
}
else
{
printf("No Hit: %dn", iSomeNumber);
}
};
ref = 2;
std::for_each(elements.begin(), elements.end(), printhit);
}
现在,我的问题是:当我使用捕获 [=] 定义 printhit 时,它会打印"命中:1"。如果我通过引用 [&] 传递它,它会打印"命中:2"。我不知何故期望,替换是在for_each内完成的,因此无论我如何授予对"ref"的访问权限,都会打印"Hit:2"。
谁能向我解释一下?
谢谢 马库斯
捕获发生在您声明 lambda 的位置。 就像在此时创建一个类对象并将其ref
传递给其构造函数一样。
您的示例等效于以下内容:
class Functor
{
public:
Functor(int r) :ref(r) {}
void operator()(int iSomeNumber) const
{
if (ref == iSomeNumber)
{
printf("Hit: %dn", iSomeNumber);
}
else
{
printf("No Hit: %dn", iSomeNumber);
}
}
private:
int ref;
};
void DoSomething()
//----------------------------------------------------------------
{
std::vector<int> elements;
elements.push_back(1);
elements.push_back(2);
int ref = 1;
Functor printhit(ref);
ref = 2;
std::for_each(elements.begin(), elements.end(), printhit);
}
我猜,C++标准的以下部分适用:
5.1.2.14:
如果实体是隐式捕获的,并且捕获默认值为 =,或者如果它是显式的,则通过 copy 捕获实体使用不包含 &.对于 copy 捕获的每个实体,一个未命名的非静态数据成员在闭包类型中声明。未指定这些成员的声明顺序。如果此类实体不是引用对象,否则引用的类型。[ 注意:如果捕获的实体是对函数,对应的数据成员也是对函数的引用。—尾注 ]
5.1.2.21:
计算 lambda 表达式时,使用 copy 捕获的实体进行直接初始化生成的闭包对象的每个对应的非静态数据成员。(对于数组成员,数组元素按下标顺序递增直接初始化。这些初始化在(未指定)声明非静态数据成员的顺序。[ 注意:这可确保破坏将按与构造相反的顺序进行。—尾注 ]
让它们都以相同的方式操作有什么意义? [=]
的要点是支持通过复制而不是通过引用捕获。
想象一下,如果[=]
不可用:如果您在定义 lambda 的代码点知道运行时值,并希望 lambda 此后使用它,那么该值如何可用于 lambda 代码? 当 DoSomething()
运行 by-ref 时,[&]
访问其局部 ref
变量可能会起作用,但是如果您希望 lambda 的生命周期在包含它的DoSomething()
中超过本地范围的寿命,或者想要更改 ref
的值而不影响将来对 lambda 的调用,该怎么办? 从概念上讲,你可以让语言禁止所有这些事情(在更改ref
或更改ref
后使用,或者在更改ref
超出范围后调用 lambda),或者程序员可以不遗余力地将ref
的值放在某个地方供 lambda 使用(例如,在堆上, 需要管理释放,或者在某些具有重新进入和线程安全问题的静态缓冲区中),但为了方便起见,该语言提供了[=]
。 编译器生成的 lambda 有效地负责存储和破坏/解除分配ref
的副本。
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 多个"常量引用"变量可以共享同一个内存吗?
- 如果非动态变量被指针引用,何时超出范围?
- 在 c++ 中将变量作为结构构造函数中的引用传递
- 在 gtest 中初始化堆栈上的引用变量的隔离错误
- 为什么C++可以使用未初始化的成员变量(引用或指针 *NOT 值复制*)来初始化其父类的成员变量
- 地址运算符是否返回变量引用的对象的地址
- 未在另一个函数中设置变量引用的问题
- 英特尔样式内联程序集和 AT&T 样式中的变量引用,C++
- 将成员变量引用为类成员
- 从静态变量引用非静态变量会使非静态变量先于静态变量进行析构函数
- 何时解析 C++11 lambda 表达式中的变量引用
- 堆栈/堆变量的变量/引用名称或类型存储在内存中的位置
- C++强制对变量引用进行编译优化,使之成为直接的
- Boost变量引用和相等比较
- 使复制的成员引用变量引用副本的成员,而不是原始成员的成员
- 为什么要在Java中生成变量引用数组
- 捕获和调试对移动lambda内部局部变量引用的无效使用
- 在变量初始化后更改变量引用
- 从'C'程序中提取变量定义和变量引用