传递lambda表达式给创建async的函数

Pass lambda expression to function that creates async

本文关键字:async 函数 创建 lambda 表达式 传递      更新时间:2023-10-16

我试图使一个类,通过独立异步消费函数。这是我的代码:

main.cpp

MPIAsyncPool pool;
MPIFuture val = pool.addTask(launch::async, [](int a) -> int {
   return a;
}, 7);
cout << "Value: " << val.get() << endl;
MPIFuture v = pool.addTask(std::launch::async, doThings, 46);
cout << "Value: " << v.get() << endl;

MPIAsyncPool (.h& . cpp)

class MPIAsyncPool {
public:
    MPIAsyncPool();
    template<typename T, typename U>
    MPIFuture addTask(std::launch, std::function<T(U...)> f, U...);
};
template<typename ReturnType, typename ArgsTypes>
MPIFuture MPIAsyncPool::addTask(std::launch launch, std::function<ReturnType(ArgsTypes...)> f, ArgsTypes... args) {
    std::future<int> fut = std::async(launch, f, args);
    return MPIFuture(fut.get());
}

声明似乎没问题,但我在定义签名方面遇到了一些问题。我错了吗?

这些是我得到的错误:

<>之前/home/query/clionprojects/MPIAsyncPool/main.cpp:在函数' int main(int, char**) '中:/home/query/clionprojects/MPIAsyncPool/main.cpp:17:15:错误:调用' MPIFuture::MPIFuture() '没有匹配的函数MPIFuture val;^/home/query/clionprojects/MPIAsyncPool/MPIAsyncPool.h:11:0从/home/quero/ClionProjects/MPIAsyncPool/main.cpp: 3:/home/query/clionprojects/MPIAsyncPool/MPIFuture .h:12:5: note: candidate: MPIFuture::MPIFuture(int)MPIFuture (int);^/home/query/clionprojects/MPIAsyncPool/MPIfuture.h:12:5:注意:candidate期望1个参数,提供0/home/query/clionprojects/MPIAsyncPool/MPIFuture .h:10:7:备注:candidate: constexpr MPIFuture::MPIFuture(const MPIFuture&)类MPIFuture {^/home/query/clionprojects/MPIAsyncPool/MPIfuture.h:10:7:注意:candidate期望1个参数,提供0/home/query/clionprojects/MPIAsyncPool/MPIFuture .h:10:7:备注:candidate: constexpr MPIFuture::MPIFuture(MPIFuture&&)/home/query/clionprojects/MPIAsyncPool/MPIfuture.h:10:7:注意:candidate期望1个参数,提供0/home/query/clionprojects/MPIAsyncPool/main.cpp:20:13:错误:调用' MPIAsyncPool::addTask(std::launch, main(int, char**)::, int) '时没有匹配的函数7)};^/home/query/clionprojects/MPIAsyncPool/main.cpp:3:0:/home/query/clionprojects/mpiasyncool/MPIAsyncPool.h:19:15:备注:candidate: template MPIFuture mpiasyncool::addTask(std::launch, std::function, U,…)MPIFuture addTask(std::launch, std::function f, U…);^/home/query/clionprojects/MPIAsyncPool/MPIAsyncPool.h:19:15:注意:模板参数演绎/替换失败:/home/query/clionprojects/MPIAsyncPool/main.cpp:20:13:注意:' main(int, char**):: '不是派生自' std::function '7)};^/home/query/clionprojects/mpiasyncool/main.cpp:22:64:错误:调用' mpiasyncool::addTask(std::launch, int (&)(int), int) '时没有匹配的函数MPIFuture v = pool。addTask(std::launch::async, doThings, 46);^/home/query/clionprojects/MPIAsyncPool/main.cpp:3:0:/home/query/clionprojects/mpiasyncool/MPIAsyncPool.h:19:15:备注:candidate: template MPIFuture mpiasyncool::addTask(std::launch, std::function, U,…)MPIFuture addTask(std::launch, std::function f, U…);^/home/query/clionprojects/MPIAsyncPool/MPIAsyncPool.h:19:15:注意:模板参数演绎/替换失败:/home/query/clionprojects/MPIAsyncPool/main.cpp:22:64:注意:不匹配的类型' std::function '和' int (*)(int) 'MPIFuture v = pool。addTask(std::launch::async, doThings, 46);^/home/query/clionprojects/MPIAsyncPool/MPIAsyncPool.cpp:14:109:错误:扩展模式argtypes不包含参数包MPIFuture MPIAsyncPool::addTask(std::launch launch, std::function f, argstype…)args) {^/home/query/clionprojects/mpiasyncool/mpiasyncool .cpp:14:11:错误:原型' MPIFuture mpiasyncool::addTask(std::launch, std::function) '不匹配任何类' mpiasyncool 'MPIFuture MPIAsyncPool::addTask(std::launch launch, std::function f, argstype…)args) {^/home/query/clionprojects/MPIAsyncPool/MPIAsyncPool.cpp:5:0:/home/query/clionprojects/mpiasyncool/MPIAsyncPool.h:19:15: error: candidate is: template MPIFuture mpiasyncool::addTask(std::launch, std::function, U,…)MPIFuture addTask(std::launch, std::function f, U…);

std::function是一种类型,其目的是类型擦除,允许您在相同类型的存储中存储多种类型的可调用值。你不能这样做。

模板类型推导是指从函数调用的实参中推导模板形参时发生的情况。你正在做这件事。

类型擦除和类型演绎是的逆。您的代码试图推断要擦除的类型,这在实际中不起作用,在理论上也很少有意义。

并且,类型擦除也在std::async中发生:类型擦除的每一层都有成本(运行时间和编译时间),所以只有当您需要在同一个变量中存储多个类型的信息时才使用它。

这是你的代码的第一次传递:

class MPIAsyncPool {
public:
  MPIAsyncPool();
  // R is the return type of F when invoked with Us...
  template<class F, class...Us, class R=typename std::result_of<F&(Us...)>::type>
  MPIFuture addTask(std::launch, F&& f, Us&&...);
};

也在.h文件中:

template<class F, class...Us, class R>
MPIFuture MPIAsyncPool::addTask(std::launch launch, F&& f, Us...us) {
  std::future<R> fut = std::async(launch, std::forward<F>(f), std::forward<Us>(us)...);
  return MPIFuture(fut.get());
}

现在,这仍然很糟糕,因为当你return时,你的阻塞了异步的。async的全部意义在于,除非你需要它,否则不要阻塞。

改变:

  return MPIFuture(fut.get());

  return MPIFuture(std::move(fut));

这可能需要修复MPIFuture,但这是有意义的签名。您希望获取std::future的状态,而不是block,并获取其值。

最后,您不能在.cpp文件中定义模板并在.cpp文件之外使用它们。这里是类型擦除的用法!

如果你真的想把实现放在.cpp文件中,并且愿意将你的代码限制为返回int的代码,我们可以这样做:

class MPIAsyncPool {
public:
  MPIAsyncPool();
  template<class F, class...Us, class R=typename std::result_of<F&(Us...)>::type>
  MPIFuture addTask(std::launch l, F f, Us...us) {
    // does not support move-only f or us...:
    return addTaskInternal(l, [=]()->int{
      return std::move(f)(std::move(us)...);
    });
  }
private:
  MPIFuture addTaskInternal(std::launch, std::function<int()>);
};
. cpp

:

MPIFuture MPIAsyncPool::addTask(std::launch launch, std::function<int()> f) {
  std::future<int> fut = std::async(launch, std::move(f));
  return MPIFuture(std::move(fut));
}

现在头文件转发到内部方法,该方法使用非模板签名。我们对lambda进行类型擦除,这样我们所记得的就是如何调用它、销毁它和复制它。这种擦除使得将其转换为"普通"方法(而不是模板方法)成为可能。

您没有发布确切的错误,但我猜这是因为您不使用可变模板,就像您应该的那样。addTask签名应该是这样的:

template<typename T, typename... U>
MPIFuture addTask(std::launch, std::function<T(U...)> f, U...);

同时,你必须在函数实现中展开参数:

std::future<int> fut = std::async(launch, f, args...);

另外,我会移动参数而不是将它们作为值传递。整体实现应该如下所示:

template<typename ReturnType, typename... ArgsTypes>
MPIFuture MPIAsyncPool::addTask(std::launch launch, const std::function<ReturnType(ArgsTypes...)>& f, ArgsTypes&&... args) {
    std::future<int> fut = std::async(launch, f, std::forward<Args>(args)...);
    return MPIFuture(fut);
}