标准库中是否有与 std::thread 的构造函数语义匹配的类型擦除函数包装器?

Is there a type-erased function wrapper in the Standard Library that matches std::thread's constructor semantics?

本文关键字:类型 擦除 函数 包装 语义 构造函数 是否 std 标准 thread      更新时间:2023-10-16

我需要创建一个非模板类¹,该类需要保存可调用对象及其参数,以便稍后调用它们。

由于此类正在对异步执行进行建模,因此我想为其提供与std::thread/std::async匹配的 API 和语义:

class Async {
public:
template <typename Function, typename... Args >
explicit Async(Function&& f, Args &&... args)
{
// perform a (decay) copy of the args,
// store f and the copy somewhere
}
void call() 
{
// to be possibly called in a different thread;
// call the function stored. no need to return the results
}
private:
// which data members?
};

我想到的第一件事是使用std::function<void()>作为唯一的数据成员,并从参数的std::bind初始化它。

但是,这不起作用:std::functionstd::bind不支持仅移动类型,std::bindstd::invoke方面根本不起作用(它做了很多额外的魔术,比如递归解析绑定)。

我是否缺少标准库中提供的一些易于访问的解决方案来实现这一点,或者我应该部署自己的绑定器和类型擦除的函数包装类?


¹ 长话短说:此类需要从具有虚拟方法的基类继承,因此将此类设置为模板类会导致通常的代码膨胀和冲突,因为虚拟表和虚拟方法无处不在的重复。

template<class T> T&& wrap_pm(T&& t) { return std::forward<T>(t); }
template<class T, class U> 
auto wrap_pm(U T::* p) -> decltype(std::mem_fn(p)) { return std::mem_fn(p); }
class Async {
public:
template <typename Function, typename... Args >
explicit Async(Function&& f, Args &&... args)
: fut(std::async(std::launch::deferred, 
[f=std::forward<Function>(f)](auto&&... args) mutable
{
wrap_pm(std::move(f))(decltype(args)(args)...); 
}, std::forward<Args>(args)...)) 
{ }
void call() 
{
fut.get();
}
private:
std::future<void> fut;
};

我对效率不作任何承诺。

从技术上讲,std::packaged_task<void()>符合您的要求。 这是严重的矫枉过正,因为它可以与线程交互并可以产生期货。

我写了一个处理仅移动调用的task,它非常简单。 正确优化小型缓冲区更加困难。

class Async {
public:
template <typename Function, typename... Args >
explicit Async(Function&& f, Args &&... args) {
task = [f=std::forward<Function>(f), args=std::make_tuple(std::forward<Args>(args)...)]()mutable{
std::apply(std::move(f), std::move(args));
};
}
void call() {
task();
task={}; // don't call twice
}
private:
std::packaged_task<void()> task;
};

我用过的地方C++17 std 适用。 只需重新实现它,使用谷歌找到一个实现。