捕获发生在构建std::function
之前。
所以你捕捉std::function<void()> func
未初始化(甚至不是默认的构造!)副本。所有其本身捕获的std::function
都是UB(在构建它之前复制一个变量!),并且调用它将甚至是“更多UB”(调用非构造的std::function
的副本!)。
的参考情况捕获参考func
,它被初始化之前也被允许的,只要它是只使用一次初始化。
缺点到参考情况是拉姆达仅保留的func
的范围内有效。一旦func
超出范围,它的副本也是无效的。根据我的经验,这很糟糕。
要做到真正的“充满力量”递归拉姆达,你需要像Y型组合子。
这里是短一个C++ 14的y组合子:
template<class F>
auto y_combinate(F&& f) {
return [f = std::forward<F>(f)](auto&&...args) {
return f(f, decltype(args)(args)...);
};
}
传递给它的是期望到自身的引用作为第一个参数的λ:
std::function<void()> func = y_combinate([](auto&& self) {
self(self);
}
);
和它的休息。
的y组合子的要求是因为你没有一个lambda体内访问自己的this
。所以我们添加一个。
上述的y组合子是只有90%的,因为它不能处理R/L值和完全通过了功能对象的常量性。但它大部分时间都会用到。
这是一个稍微好一点的y combinate:
template<class F>
struct y_combinate_t {
F f;
template<class...Args>
decltype(auto) operator()(Args&&...args)const {
return f(*this, std::forward<Args>(args)...);
}
};
template<class F>
y_combinate_t<std::decay_t<F>> y_combinate(F&& f) {
return {std::forward<F>(f)};
}
这使得使用好一点:
std::function<void()> func = y_combinate([](auto&& self) {
self();
}
);
调用时在现已通过了self
不必传递self
本身。
第二个片段复制一个尚未初始化的值,因此它尚未“活着”。 –
@Alex函数没有被调用,所以它只应该创建lambda函数,然后退出。 –
@KerrekSB啊!因此,使用'&func'可以工作,因为它只复制lambda函数的地址?直到现在我还不明白捕获是否真的像函数参数。 –