【发布时间】:2018-07-25 02:10:17
【问题描述】:
当函子实际上只使用隐式捕获对象的某些数据成员时,编译器允许从按值默认捕获中省略什么?例如,
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 大小的可见外部影响,但我不知道在规范中的哪里可以找到允许哪些优化的答案.
【问题讨论】:
-
请注意,as-if 规则始终适用:即使捕获了所有
a,编译器也只需确保程序的输出与理论输出匹配,因此它可以决定不复制a.z。 -
我对 as-if 规则在复制 lambdas 时如何运作特别模糊,因为捕获的元素可能具有可见的 ctor/dtor 副作用等。我有一半的预期是这里的大多数优化是允许的,但我怀疑会禁止部分复制的交互集相当大和微妙。
-
好吧,如果捕获元素会有可见的副作用,那么这些副作用必然是捕获的结果。如果您的
A具有非默认复制构造函数,则必须调用该复制构造函数。如果编译器可以证明在执行构造函数之后不需要简单地复制捕获的类的一些其他成员,那么编译器就不需要经历实际这样做的动作。但它仍然必须调用复制构造函数,“好像”整个实例是按值捕获的。 -
std::array<bool,N>没有任何可见的副作用