我正在尝试创建一个通过实例化异步来使用函数的类。那是我的代码:
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...);
最佳答案
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 MPIFuture(fut.get());
到
return MPIFuture(std::move(fut));
这可能需要修复 MPIFuture
,但这是有意义的签名。你想获取 std::future
的状态,而不是阻塞并获取它的值。
最后,您不能在 .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 进行类型删除,以便我们只记得如何调用它、销毁它和复制它。这种删除使得将其变成“普通”方法(而不是模板方法)成为可能。
关于c++ - 将 lambda 表达式传递给创建异步的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31413150/