假装packaged_task是可复制构造的

时间:2015-01-04 12:33:22

标签: c++ c++11 asynchronous

我一直在寻找problem of type-erasing a std::packaged_task using std::function的解决方法。

我想做的是这样的事情:

#include <future>
#include <functional>
#include <iostream>

namespace {
  std::function<void()> task;
  std::future<int> make(int val) {
    auto test = std::packaged_task<int()>([val](){
      return val;
    });

    auto fut = test.get_future();
    task = std::move(test);
    return fut;
  }
}

int main() {
   auto fut = make(100);
   task();
   std::cout << fut.get() << "\n";
}
它简洁明了,避免自己重新实施很多机制。不幸的是,这实际上并不合法,因为std::packaged_task只是移动而不是可复制的。

作为一种解决方法,我想出了以下内容,它实现了std::promisestd::shared_ptr方面的内容:

#include <future>
#include <functional>
#include <iostream>

namespace {
  std::function<void()> task;

  std::future<int> make(int val) {
    auto test = std::make_shared<std::promise<int>>();

    task = [test,val]() {
      test->set_value(val);
      test.reset(); // This is important
    };

    return test->get_future();
  }
}

int main() {
   auto fut = make(100);
   task();
   std::cout << fut.get() << "\n";
}

这“对我有用”,但这实际上是正确的代码吗?有没有更好的方法来实现相同的净结果?

(请注意,第二个示例中std::shared_ptr的生命周期对于我的实际代码非常重要。显然,我将采取措施防止两次调用相同的std::function

1 个答案:

答案 0 :(得分:1)

您的问题似乎源于类型不兼容性:

std::function<void()> task;  // Notice this is not a package_task

那你为什么期望这个有用?

task = std::move(test);  // when test is `std::packaged_task<int()>`

当我将任务更改为正确的类型时,它会按预期编译:

namespace {

  std::packaged_task<int()> task;          // Change this.

  std::future<int> make(int val) {
    auto test = std::packaged_task<int()>([val](){
      return val;
    });

    auto fut = test.get_future();
    task = std::move(test);              // This now compiles.
    return fut;
  }
}

就个人而言,因为类型很重要,我会从auto删除test

namespace {

    std::packaged_task<int()> task;

    std::future<int> make(int val) {
        std::packaged_task<int()> test([val](){return val;});

        auto fut = test.get_future();
        task     = std::move(test);
        return fut;
    }
}