当函子实际上仅使用隐式捕获对象的某些数据成员时,编译器允许从按值缺省捕获中忽略什么?例如,
struct A {
// some members we care about:
char x;
int y;
// some huge amount of state we do not:
std::array<bool, 200000> z;
int foo() const { return y + 1 }
};
void bar() {
A a;
// must the entirety of a be copy captured, or is the compiler allowed to pick/prune?
auto l1 = [=](){ std::cout << a.x << ", " << a.y << std::endl; };
// ...
}
类似地,何时允许早期评估省略更广泛的捕获?
void baz(int i) {
A a2;
a2.y = i;
// capture fundamentally only needs 1 int, not all of an A instance.
auto l2 = [=](){ std::cout << a.foo() << std::endl; }
}
至少在某些情况下,对元素进行部分或完全复制捕获应该不会超出lambda大小而没有可见的外部影响,但是我不知道在规范中何处寻找允许哪些优化的答案
答案 0 :(得分:3)
我认为,原则上,将允许编译器以某种方式优化此方式,该方式将仅在as-if规则下捕获使用的成员的副本。 [expr.prim.lambda] §2的相关部分:
[…]实现可以定义闭包类型,其方式与以下描述不同,前提是该闭包类型除了更改以外不会改变程序的可观察行为:
- 闭合类型的大小和/或对齐方式
- 关闭类型是否可以简单复制,或者
- 闭合类型是否为标准布局类。
但是,在对闭包类型的sizeof()
进行快速测试时,似乎没有一个主要的编译器(clang,gcc,msvc)以这种方式优化闭包类型。
不过,应该注意的是,只有将从lambda表达式获得的对象实际存储在某个地方(例如,放在std::function
中)后,这才真正成为问题。通常,lambda表达式的结果将仅用作某些函数模板的参数,然后被丢弃。在这种情况下,所有内容最终都被内联,优化器应该(并且在我的测试中这样做)只是丢弃生成的代码,用于围绕从未引用的数据进行复制……