将lambda表达式传递给创建异步的函数

时间:2015-07-14 17:13:23

标签: c++ lambda task future

我正在尝试通过异步化asyncs来创建一个消耗函数的类。那是我的代码:

的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/quero/ClionProjects/MPIAsyncPool/main.cpp: In function ‘int main(int, char**)’:
/home/quero/ClionProjects/MPIAsyncPool/main.cpp:17:15: error: no matching function for call to ‘MPIFuture::MPIFuture()’
     MPIFuture val;
               ^
In file included from /home/quero/ClionProjects/MPIAsyncPool/MPIAsyncPool.h:11:0,
                 from /home/quero/ClionProjects/MPIAsyncPool/main.cpp:3:
/home/quero/ClionProjects/MPIAsyncPool/MPIfuture.h:12:5: note: candidate: MPIFuture::MPIFuture(int)
     MPIFuture(int);
     ^
/home/quero/ClionProjects/MPIAsyncPool/MPIfuture.h:12:5: note:   candidate expects 1 argument, 0 provided
/home/quero/ClionProjects/MPIAsyncPool/MPIfuture.h:10:7: note: candidate: constexpr MPIFuture::MPIFuture(const MPIFuture&)
 class MPIFuture {
       ^
/home/quero/ClionProjects/MPIAsyncPool/MPIfuture.h:10:7: note:   candidate expects 1 argument, 0 provided
/home/quero/ClionProjects/MPIAsyncPool/MPIfuture.h:10:7: note: candidate: constexpr MPIFuture::MPIFuture(MPIFuture&&)
/home/quero/ClionProjects/MPIAsyncPool/MPIfuture.h:10:7: note:   candidate expects 1 argument, 0 provided
/home/quero/ClionProjects/MPIAsyncPool/main.cpp:20:13: error: no matching function for call to ‘MPIAsyncPool::addTask(std::launch, main(int, char**)::, int)’
         }, 7);
             ^
In file included from /home/quero/ClionProjects/MPIAsyncPool/main.cpp:3:0:
/home/quero/ClionProjects/MPIAsyncPool/MPIAsyncPool.h:19:15: note: candidate: template MPIFuture MPIAsyncPool::addTask(std::launch, std::function, U, ...)
     MPIFuture addTask(std::launch, std::function f, U...);
               ^
/home/quero/ClionProjects/MPIAsyncPool/MPIAsyncPool.h:19:15: note:   template argument deduction/substitution failed:
/home/quero/ClionProjects/MPIAsyncPool/main.cpp:20:13: note:   ‘main(int, char**)::’ is not derived from ‘std::function’
         }, 7);
             ^
/home/quero/ClionProjects/MPIAsyncPool/main.cpp:22:64: error: no matching function for call to ‘MPIAsyncPool::addTask(std::launch, int (&)(int), int)’
     MPIFuture v = pool.addTask(std::launch::async, doThings, 46);
                                                                ^
In file included from /home/quero/ClionProjects/MPIAsyncPool/main.cpp:3:0:
/home/quero/ClionProjects/MPIAsyncPool/MPIAsyncPool.h:19:15: note: candidate: template MPIFuture MPIAsyncPool::addTask(std::launch, std::function, U, ...)
     MPIFuture addTask(std::launch, std::function f, U...);
               ^
/home/quero/ClionProjects/MPIAsyncPool/MPIAsyncPool.h:19:15: note:   template argument deduction/substitution failed:
/home/quero/ClionProjects/MPIAsyncPool/main.cpp:22:64: note:   mismatched types ‘std::function’ and ‘int (*)(int)’
     MPIFuture v = pool.addTask(std::launch::async, doThings, 46);
                                                                ^
/home/quero/ClionProjects/MPIAsyncPool/MPIAsyncPool.cpp:14:109: error: expansion pattern ‘ArgsTypes’ contains no argument packs
 MPIFuture MPIAsyncPool::addTask(std::launch launch, std::function f, ArgsTypes... args) {
                                                                                                             ^
/home/quero/ClionProjects/MPIAsyncPool/MPIAsyncPool.cpp:14:11: error: prototype for ‘MPIFuture MPIAsyncPool::addTask(std::launch, std::function)’ does not match any in class ‘MPIAsyncPool’
 MPIFuture MPIAsyncPool::addTask(std::launch launch, std::function f, ArgsTypes... args) {
           ^
In file included from /home/quero/ClionProjects/MPIAsyncPool/MPIAsyncPool.cpp:5:0:
/home/quero/ClionProjects/MPIAsyncPool/MPIAsyncPool.h:19:15: error: candidate is: template MPIFuture MPIAsyncPool::addTask(std::launch, std::function, U, ...)
     MPIFuture addTask(std::launch, std::function f, U...);

2 个答案:

答案 0 :(得分:1)

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 阻止在异步上时。并且在您需要之前,异步的整个点都不会阻塞。

变化:

  return MPIFuture(fut.get());

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

这可能需要修复MPIFuture,但这是有意义的签名。你想采取std::future的状态,而不是阻止并获得它的价值。

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

如果确实想要将实现放在.cpp文件中,并且愿意将代码限制为返回int的代码,我们可以这样做:< / p>

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()>);
};

in .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,以便我们记住它是如何调用它,销毁它并复制它。这种擦除可以将其变成正常的&#34;方法(不是模板方法)。

答案 1 :(得分:0)

你没有发布确切的错误,但我猜测它是因为你没有像你应该那样使用可变参数模板。 addTask签名应该看起来像

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

另外,您必须在函数实现中扩展args:

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

加上,我会移动参数aroung而不是将它们作为值传递。 整体实施应该如下:

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);
}