首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >取代std::功能从内部(通过移动-分配到*这个?)

取代std::功能从内部(通过移动-分配到*这个?)
EN

Stack Overflow用户
提问于 2018-05-28 14:38:34
回答 2查看 223关注 0票数 4

是否可以将一个std::function从内部替换为另一个std::function

以下代码未编译:

代码语言:javascript
复制
#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‘--我完全理解这一点。然而,我不知道我怎么能捕捉到functhis-pointer。我想,它甚至还不是兰达内部的std::function?!这是怎么做到的?

背景:我想要实现的是:在第一次调用给定的std::function时,我想做一些初始化工作,然后用优化的函数替换原来的函数。我想为我的功能的用户透明地实现这一点。

上面示例的预期输出是:

一个 B B

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-05-28 15:00:10

不能在lambda中使用this来引用lambda。this将只引用封闭类,在您的示例中,没有类,因此不能使用this。然而,您可以做的是捕获func并重新分配:

代码语言:javascript
复制
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超出其作用域(例如,通过按值从函数返回它)而不首先调用它(实际上重新分配了存储的函数对象),那么您将得到一个悬空引用。

我想,它甚至不是一个std::function在兰博达,现在?!

实际上是的。名称在其声明器之后进入作用域,因此在=之前引入了类型为std::function<void()>func。因此,在引入lambda的时候,您已经可以捕获func了。

票数 5
EN

Stack Overflow用户

发布于 2018-05-28 17:57:59

这在技术上解决了您的问题:

代码语言:javascript
复制
std::function<void()> func = [&func]{
  std::cout << "a\n";
  func = []{ std::cout << "b\n"; };
};

但这不是一个好计划。std函数的生存期和行为与局部级堆栈变量相关联。拷贝几乎在任何意义上都不能完成你想做的事情--它们继续打印"a\b",除非它们分段错误,因为原始的func超出了范围。

为了解决这一问题,我们必须部署一些大型武器;首先,函数式编程女王Y Combinator女士:

代码语言:javascript
复制
std::function<void()> func = y_combinate( [](auto&& self){
  std::cout << "a\n";
  self = []{ std::cout << "b\"; };
} );

Y组合器接受签名F = (F,Args...)->R的函数,然后返回签名(Args...)->R的函数。这是无状态语言如何管理递归时,您不能命名为您自己之前给您的名字。

在C++中编写Y组合器比您担心的要容易:

代码语言:javascript
复制
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印刷灯是一种不相关的类型。因此,当您尝试self = []{ std::cout << "b\n"; }时,您会得到一个错误,嵌入到一些相对较深的模板垃圾邮件错误中。

悲伤,但只是暂时的挫折。

我们需要的是一种很难命名的类型--一个F = std::function<void(F)> --一个以同一类型的对象的实例作为其一个参数的std::function

通常没有办法做到这一点,但有一点模版愚昧.在这里,我做到了之前。

然后,您的代码如下:

代码语言:javascript
复制
std::function<void()> func = y_combinate( recursive_func< void(own_type&) >([](auto&& self){
  std::cout << "a\n";
  self = [](auto&&){ std::cout << "b\n"; };
}) );

对给定的func副本的调用首先打印"a\n",然后每个调用都打印"b\n"。B-打印机的副本也打印b,但是a-打印机的副本将在转换之前第一次打印。

实例化

此代码中的self是一个recursive_func< void(own_type&) >,因此您可以在b-打印机中执行与在a-打印机中相同的操作。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50568739

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档