![](/img/trans.png)
[英]How to force std::sort to use move constructor and move-assignment?
[英]Replacing std::function from within itself (by move-assignment to *this?)
是否可以用另一个std::function
替换其中的一个std::function
?
以下代码无法编译:
#include <iostream>
#include <functional>
int main()
{
std::function<void()> func = []()
{
std::cout << "a\n";
*this = std::move([]() { std::cout << "b\n"; });
};
func();
func();
func();
}
可以修改编译吗?
现在的错误信息是: 这个lambda函数没有捕获'this' - 我完全理解。 然而,我不知道如何捕获func
的this
指针。 我猜,它甚至不是lambda中的std::function
,但是?! 如何才能做到这一点?
背景:我想要实现的是:在第一次调用给定的std::function
,我想做一些初始化工作,然后用优化的函数替换原始函数。 我想为我的功能用户透明地实现这一点。
上面例子的预期输出是:
一种
b
b
你不能在lambda中使用this
来引用lambda。 this
只会引用封闭类,在你的情况下没有,所以你不能使用this
。 但你可以做的是捕获func
并重新分配:
std::function<void()> func = [&func]()
{
std::cout << "a\n";
func = []() { std::cout << "b\n"; }; // note the missing move, a lambda
// is already an rvalue
};
但请注意,如果你让func
比它的范围更长(比如通过值从函数返回它)而不先调用它(有效地重新分配存储的函数对象),那么你将获得一个悬空引用。
我猜,它甚至不是lambda中的
std::function
,但是?!
它实际上是。 名称在其声明符后立即进入作用域,所以在=
之前,引入了类型为std::function<void()>
func
。 因此,在您引入lambda的时候,您已经可以捕获func
。
这在技术上解决了您的问题:
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组合器比在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)};
}
遗憾的是,这不起作用,因为传递给lambda的self
类型实际上是原始lambda的类型。 而b-printing lambda是一种不相关的类型。 所以当你尝试self = []{ std::cout << "b\\n"; }
self = []{ std::cout << "b\\n"; }
你嵌入在一些比较深的模板垃圾错误的错误。
伤心; 但只是暂时的挫折。
我们需要的是一个非常难以命名的类型 - 一个F = std::function<void(F)>
- 一个std::function
,它将一个参数作为同一类型的对象的一个实例。
通常没有办法做到这一点,但有一些模板tomfoolery ... 在这里,我之前做过 。
那你的代码是:
std::function<void()> func = y_combinate( recursive_func< void(own_type&) >([](auto&& self){
std::cout << "a\n";
self = [](auto&&){ std::cout << "b\n"; };
}) );
并且对func
的给定副本的func
首先打印"a\\n"
,然后每个稍后的调用打印"b\\n"
。 b打印机的副本也打印b,但是a-printers的副本将在转换之前第一次打印。
实例 。
此代码中的self
是recursive_func< void(own_type&) >
,因此您可以在b-printer中执行与a-printer中相同的操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.