c++ - std::async 与共享指针模板化成员函数
问题描述
我正在一个项目中实现多线程,但是当涉及到 std::async 的一些更复杂的使用时,我遇到了困难。我想在模板化对象上调用成员函数并将参数作为参数传递,但是当模板包含共享指针时我无法让它工作。
在成员函数上使用 std::async 非常简单,甚至是模板化的成员函数。对于这种特定用途,我已经看到很多关于堆栈溢出的答案。我什至自己运行了一些测试用例:
#include <thread>
#include <future>
#include <iostream>
class Bar
{
public:
Bar () {}
double data;
};
template <typename T>
class Foo
{
public:
Foo () {}
T set_data (T d) { data = d; return data; }
private:
T data;
};
#include "./foo.h"
#include <memory>
int main (int argc, char **argv)
{
/**
* Works fine
*/
Foo<int> foo1;
auto fut1 = std::async(std::launch::async, &Foo<int>::set_data, &foo1, 42);
fut1.wait();
std::cout << fut1.get() << std::endl;
return 0;
}
此示例在 gcc 7.4.0 中编译得非常好,并按预期返回 42。
当我在模板中使用 shared_ptr 时,我的问题就出现了。使用上面相同的 Foo 和 Bar 类:
#include "./foo.h"
#include <memory>
int main (int argc, char **argv)
{
/**
* Doesn't work
*/
auto foo2 = std::make_shared<Foo<std::shared_ptr<Bar>>>;
auto br = std::make_shared<Bar>;
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data, &foo2, bar);
fut2.wait();
std::cout << fut2.get()->data << std::endl;
return 0;
}
编译时出现此错误g++ -pthread test.cpp -o test
test.cpp: In function ‘int main(int, char**)’:
test.cpp:20:94: error: no matching function for call to ‘async(std::launch, std::shared_ptr<Bar> (Foo<std::shared_ptr<Bar> >::*)(std::shared_ptr<Bar>), Foo<std::shared_ptr<Bar> >*, std::shared_ptr<Bar> (*&)())’
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data, &foo2, bar);
^
In file included from ./foo.h:2:0,
from test.cpp:1:
/usr/include/c++/7/future:1712:5: note: candidate: template<class _Fn, class ... _Args> std::future<typename std::result_of<typename std::decay<_Tp>::type(typename std::decay<_Args>::type ...)>::type> std::async(std::launch, _Fn&&, _Args&& ...)
async(launch __policy, _Fn&& __fn, _Args&&... __args)
^~~~~
/usr/include/c++/7/future:1712:5: note: template argument deduction/substitution failed:
/usr/include/c++/7/future: In substitution of ‘template<class _Fn, class ... _Args> std::future<typename std::result_of<typename std::decay<_Tp>::type(typename std::decay<_Args>::type ...)>::type> std::async(std::launch, _Fn&&, _Args&& ...) [with _Fn = std::shared_ptr<Bar> (Foo<std::shared_ptr<Bar> >::*)(std::shared_ptr<Bar>); _Args = {Foo<std::shared_ptr<Bar> >*, std::shared_ptr<Bar> (*&)()}]’:
test.cpp:20:94: required from here
/usr/include/c++/7/future:1712:5: error: no type named ‘type’ in ‘class std::result_of<std::shared_ptr<Bar> (Foo<std::shared_ptr<Bar> >::*(Foo<std::shared_ptr<Bar> >*, std::shared_ptr<Bar> (*)()))(std::shared_ptr<Bar>)>’
/usr/include/c++/7/future:1745:5: note: candidate: template<class _Fn, class ... _Args> std::future<typename std::result_of<typename std::decay<_Tp>::type(typename std::decay<_Args>::type ...)>::type> std::async(_Fn&&, _Args&& ...)
async(_Fn&& __fn, _Args&&... __args)
^~~~~
/usr/include/c++/7/future:1745:5: note: template argument deduction/substitution failed:
/usr/include/c++/7/future: In substitution of ‘template<class _Fn, class ... _Args> std::future<typename std::result_of<typename std::decay<_Tp>::type(typename std::decay<_Args>::type ...)>::type> std::async(_Fn&&, _Args&& ...) [with _Fn = std::launch; _Args = {std::shared_ptr<Bar> (Foo<std::shared_ptr<Bar> >::*)(std::shared_ptr<Bar>), Foo<std::shared_ptr<Bar> >*, std::shared_ptr<Bar> (*&)()}]’:
test.cpp:20:94: required from here
/usr/include/c++/7/future:1745:5: error: no type named ‘type’ in ‘class std::result_of<std::launch(std::shared_ptr<Bar> (Foo<std::shared_ptr<Bar> >::*)(std::shared_ptr<Bar>), Foo<std::shared_ptr<Bar> >*, std::shared_ptr<Bar> (*)())>’
我认为这可能是因为引用 & 没有按照模板的所有尖括号以正确的顺序工作,所以我尝试使用一些括号:
#include "./foo.h"
#include <memory>
int main (int argc, char **argv)
{
/**
* Doesn't work
*/
Foo<std::shared_ptr<Bar>> foo2;
Bar bar;
auto fut2 = std::async(std::launch::async, &(Foo<std::shared_ptr<Bar>>::set_data), &foo2, bar);
fut2.wait();
std::cout << fut2.get().data << std::endl;
return 0;
}
这会导致更短的错误,我也不明白。
test.cpp: In function ‘int main(int, char**)’:
test.cpp:20:75: error: invalid use of non-static member function ‘T Foo<T>::set_data(T) [with T = std::shared_ptr<Bar>]’
auto fut2 = std::async(std::launch::async, &(Foo<std::shared_ptr<Bar>>::set_data), &foo2, bar);
我很困惑为什么共享指针突然有所不同,我猜它与类型推导有关?任何帮助表示赞赏。
编辑
感谢那些回应的人,这是解决方案。括号不是必需的,并且缺少一些 shared_ptrs。
#include "./foo.h"
#include <memory>
int main (int argc, char **argv)
{
Foo<std::shared_ptr<Bar>> foo2;
auto bar = std::make_shared<Bar>(2.5);
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data), &foo2, bar;
fut2.wait();
std::cout << fut2.get()->data << std::endl;
return 0;
}
解决方案
有一些问题,我认为使用 lambda 可能会帮助您澄清发生了什么:
int main (int argc, char **argv)
{
Foo<std::shared_ptr<Bar>> foo2;
Bar bar;
auto op = [foo2, bar]() mutable {return foo2.set_data(std::make_shared<Bar>(bar));};
auto fut2 = std::async(std::launch::async, op);
fut2.wait();
std::cout << fut2.get()->data << std::endl;
return 0;
}
你必须传递给set_data
a shared_ptr
to Foo
。其次,set_data
不是 const 限定的,所以你需要一个可变的 lambda。最后,future 在返回get()
时会给你一个shared_ptr
toBar
所以你需要 operator ->
。您可以使代码在 lambda 内部更有效地移动Foo2
,Bar
但我试图保持答案简单,特别是因为我不知道您是否希望在您的用例中重新使用Foo2
and Bar
,但您可以考虑在内部移动拉姆达。
关于您的具体代码,以下是使用 C++14 在 g++ 9.1 中编译,请参阅https://godbolt.org/z/DFZLtb
int main (int argc, char **argv)
{
Foo<std::shared_ptr<Bar>> foo2;
Bar bar;
auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data, &foo2, std::make_shared<Bar>());
fut2.wait();
std::cout << fut2.get()->data << std::endl;
return 0;
}
您需要提供 a shared_ptr<Bar>
as 参数而不是 aBar
并且您需要删除Foo<std::shared_ptr<Bar>>::set_data
.
推荐阅读
- visual-studio-code - 等待 CouchDB 容器启动
- laravel - Nova中的数组到字符串转换
- mysql - 我们已经使用 phpmyadmin 5.0 从 Mariadb 10.1.21 迁移到 mysql 5.6。迁移后,我们面临存储过程中的问题
- c++ - 链接时跳过带有未显式引用但可通过工厂获得的类的库的目标文件
- reactjs - Google React 图表放置和图例放置
- python - 运行时是否可以防止无头Chrome窗口启动?
- python - 从熊猫列表系列中提取元素并存储为单独的系列
- php - 使用 Doctrine 的顺序连接表
- django - Django Forms 中的标签不会更改其名称
- intellij-idea - Intellij vim 仿真退格不起作用