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

C++ 标准库中是否有与std::thread'匹配的类型擦除函数包装器;什么是构造函数语义?,c++,c++11,stdthread,C++,C++11,Stdthread,我需要创建一个非模板类,它需要保存一个可调用函数及其参数,以便在以后调用它们 由于该类正在对异步执行进行建模,因此我想为它提供与std::thread/std::async匹配的API和语义: class Async { public: template <typename Function, typename... Args > explicit Async(Function&& f, Args &&... args) {

我需要创建一个非模板类,它需要保存一个可调用函数及其参数,以便在以后调用它们

由于该类正在对异步执行进行建模,因此我想为它提供与
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?
};
类异步{
公众:
样板
显式异步(函数和函数、参数和…参数)
{
//执行args的(衰减)副本,
//把f和副本存放在某处
}
无效调用()
{
//在不同的线程中可能被调用;
//调用存储的函数。无需返回结果
}
私人:
//哪些数据成员?
};
我想到的第一件事是使用
std::function
作为唯一的数据成员,并通过参数从
std::bind
初始化它

但是,这不起作用:
std::function
std::bind
不支持仅移动类型,而且
std::bind
std::invoke
方面根本不起作用(而且它还有很多额外的魔力,比如递归解析绑定)

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



➣长话短说:该类需要从具有虚拟方法的基类继承,因此将该类设为模板类将导致常见的代码膨胀和冲突,因为到处都出现虚拟表和虚拟方法的重复。

从技术上讲
std::packaged_task
符合您的要求。这是严重的过度使用,因为它可以与线程交互并产生未来

我已经编写了一个
任务
,它只处理move调用,非常简单。正确地进行小缓冲区优化比较困难

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;
};
类异步{
公众:
样板
显式异步(函数和函数、参数和…参数){
task=[f=std::forward(f),args=std::make_tuple(std::forward(args)…])()可变{
std::apply(std::move(f),std::move(args));
};
}
无效调用(){
任务();
task={};//不要调用两次
}
私人:
std::打包的任务;
};

我使用C++17标准应用程序的地方。只需重新实现它,就可以使用google找到一个实现。

从技术上讲
std::packaged_任务
符合您的要求。这是严重的过度使用,因为它可以与线程交互并产生未来

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;
};
我已经编写了一个
任务
,它只处理move调用,非常简单。正确地进行小缓冲区优化比较困难

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;
};
类异步{
公众:
样板
显式异步(函数和函数、参数和…参数){
task=[f=std::forward(f),args=std::make_tuple(std::forward(args)…])()可变{
std::apply(std::move(f),std::move(args));
};
}
无效调用(){
任务();
task={};//不要调用两次
}
私人:
std::打包的任务;
};
我使用C++17标准应用程序的地方。只需重新实现它,就可以使用google找到一个实现。

template T&&wrap\pm(T&&T){return std::forward(T);}
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;
};
样板 自动换行pm(ut::*p)->decltype(std::mem_fn(p)){return std::mem_fn(p);} 类异步{ 公众: 样板 显式异步(函数和函数、参数和…参数) :fut(std::async(std::launch::deferred), [f=std::forward(f)](自动和参数)可变 { 换行符pm(std::move(f))(decltype(args)(args)…); },std::forward(args)…) { } 无效调用() { fut.get(); } 私人: 标准:未来未来未来; };
我不保证效率。

template T&&wrap_pm(T&&T){return std::forward(T);}
样板
自动换行pm(ut::*p)->decltype(std::mem_fn(p)){return std::mem_fn(p);}
类异步{
公众:
样板
显式异步(函数和函数、参数和…参数)
:fut(std::async(std::launch::deferred),
[f=std::forward(f)](自动和参数)可变
{
换行符pm(std::move(f))(decltype(args)(args)…);
},std::forward(args)…)
{ }
无效调用()
{
fut.get();
}
私人:
标准:未来未来未来;
};

我不保证效率。

std::unique\u ptr
使用lambda而不是
std::bind
@Zereges:并将其保存到什么中?@peppe lambda可转换为
std::function
。但是
std::function
不能只存储move lambda。还是我遗漏了什么?
std::unique\u ptr
使用lambda而不是
std::bind
@Zereges:并将其保存到什么中?@peppe lambda可转换为
std::function
。但是
std::function
不能只存储移动lambda。或者我遗漏了什么?对,我真正需要的是
打包任务的一些“构建块”
。标准图书馆里有什么吗?(另外,我将在
打包的_任务
中存储什么?一个lambda,捕获函数和参数(在一个元组中,在decation_copy之后),它的主体只是调用
apply
?)我现在正在讨论这个解决方案(尽管它不能满足最初的问题)。我还添加了一个对
(void)task.get_future().get()
的调用,使其重新调用异常,尝试模拟
std::thread
…对,我真正需要的是
打包的任务的一些“构建块”
。标准图书馆里有什么吗?(还有,我应该在
打包的_任务
中存储什么?一个lambda,捕获函数和参数(在一个元组中,在decation_copy之后),它的主体只是调用
apply
?)我现在正在讨论这个解决方案(尽管它不满足