这在技术上解决了您的问题:
std::function<void()> func = [&func]{
std::cout << "a\n";
func = []{ std::cout << "b\n"; };
};
但这不是一个好的计划。std 函数的生命周期和行为与本地堆栈变量相关联。副本几乎在任何意义上都无法完成您可能想要的操作——"a\b"
除非由于原件func
超出范围而出现段错误,否则它们会继续打印。
为了解决这个问题,我们必须部署一些大炮;首先,函数式编程女王 Y Combinator 女士:
std::function<void()> func = y_combinate( [](auto&& self){
std::cout << "a\n";
self = []{ std::cout << "b\"; };
} );
Y Combinator 接受一个签名函数F = (F,Args...)->R
,然后返回一个签名函数(Args...)->R
。当您在获得名称之前无法命名自己时,这就是无状态语言管理递归的方式。
编写 Y Combinator 比在 C++ 中担心的要容易:
template<class F>
struct y_combinator_t {
F f;
template<class...Args>
auto operator()(Args&&...args)
-> typename std::result_of< F&( F&, Args&&... ) >::type
{
return f( f, std::forward<Args>(args)... );
}
};
template<class F>
y_combinator_t<typename std::decay<F>::type> y_combinate( F&& f ) {
return {std::forward<F>(f)};
}
遗憾的是,这不起作用,因为self
传递给 lambda 的类型实际上是原始 lambda 的类型。而 b-printing lambda 是一种不相关的类型。因此,当您尝试self = []{ std::cout << "b\n"; }
在一些相对较深的模板垃圾邮件错误中嵌入错误时。
伤心; 但只是暂时的挫折。
我们需要的是一种很难命名的类型——a F = std::function<void(F)>
——a std::function
,它的一个参数是一个相同类型的对象的实例。
通常没有办法做到这一点,但有点模板愚蠢......在这里,我以前做过。
然后你的代码如下:
std::function<void()> func = y_combinate( recursive_func< void(own_type&) >([](auto&& self){
std::cout << "a\n";
self = [](auto&&){ std::cout << "b\n"; };
}) );
并调用给定的func
第一个 prints副本"a\n"
,然后每个后续调用 prints "b\n"
。b 打印机的副本也打印 b,但 a 打印机的副本将在转换前第一次打印 a。
活生生的例子。
self
在此代码中是 a recursive_func< void(own_type&) >
,因此您可以在 b 打印机中执行与在 a 打印机中相同的操作。