Я работаю над реализацией многопоточности в проекте, но наталкиваюсь на стену, когда речь заходит о некоторых более сложных применениях 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);
Я смущен, почему общие указатели вдруг имеют значение, и я предполагаю, что это связано с выводом типа? Любая помощь приветствуется.
EDIT
Спасибо тем, кто откликнулся, вот решение. Скобки не обязательны, а некоторые 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;
}