【发布时间】:2019-05-21 12:22:25
【问题描述】:
到目前为止,在查看 C++ lambda expressions in the c++11 style 时,我已将它们全部归为两大类:捕获和非捕获。
非捕获 lambda 虽然在编写方式上受到更多限制,但在使用方式上却更加灵活——它们可以是implicitly converted to analogous function-pointer types;他们不鼓励无偿使用std::function<…>,他们的实现范围是less likely to creep out and cause side-effect problems,等等。
然而,捕获 lambda 可以用更广泛的方式编写。诚然,它们并没有带来我刚才提到的所有这些好处。但是捕获 lambda 弥补了它可以解决的范围广泛的问题,突破了堆栈的前馈函数调用 DAG 的限制,并以无数形式访问周围的范围。
不过,就我的理解而言。当我使用捕获 lambda 时,当我需要一到两个变量时,我倾向于显式引用捕获特定变量:
using lambda_t = std::function<std::add_pointer_t<void>(int)>;
lambda_t lambda_explicit = [&one, &another](int descriptor) {
return ::mmap(nullptr, one, PROT_READ, MAP_PRIVATE, descriptor, another);
};
...如果有两个以上,我更喜欢(出于同等的句法强迫症和懒惰)避免明确命名的捕获,而支持对所有内容的引用形式:
lambda_t lambda_everything = [&](int descriptor) {
return ::mmap(nullptr, one, PROT_READ, MAP_PRIVATE, descriptor, another);
};
... 请注意,更改 lambda 捕获的形式并不会改变任何关于 lambda 类型的明显内容——例如,调用签名是相同的。这是违反直觉的,因为 much of the way capturing works is vaguely specified and somewhat implementation-specific 似乎与捕获表达式(或者它是一个声明?还是一个声明列表?...会看到,如果你转到最后一个链接并向下滚动一点。
我什至没有触及绝大多数可能性——我几乎总是只做任何一个:
- 根本不捕获;
- 一个或两个通过引用捕获的明确命名的变量;或
- 不加选择地通过引用捕获所有内容:
[&]
在什么情况下我应该特意使用一种捕获形式而不是另一种捕获形式?
哪些形式是特殊情况,一般应避免使用?哪些有明显的惩罚——在性能、代码大小、潜在的 UB 或其他方面?是否有任何捕获表格具有切实和/或简单的好处?
【问题讨论】:
-
请注意
[&]不会捕获所有内容。它捕获所有使用过的东西。 -
说实话,我不太确定您要问什么。 FWIW 我通常会分享您的方法,纯粹是因为我喜欢直言不讳,直到它过于繁琐而不值得。 (虽然我在成员函数中也是
[=]的粉丝) -
"[..] 不要鼓励无偿使用 std::function",你不必使用
std::function,你可以简单地使用auto而不是你不需要的lambda_t。 -
@Jarod42 我认为该声明假设了一些尚未传达的上下文。就像存放在容器中一样。您可以(在运行时)将函数指针存储到容器中具有相同签名的不同 lambda 中,但对于不同的捕获 lambda,您不能这样做。
-
有一个明显的问题,即通过引用捕获会阻止 lambda 在创建引用变量的范围消失后被调用。当 lambda 尝试以任何方式使用现在无效的引用时,任何此类调用都会邀请 UB。
标签: c++ c++11 lambda scope rvalue-reference