简体   繁体   English

std :: async与共享指针模板成员函数

[英]std::async with shared pointer templated member functions

I'm working on implementing multi-threading in a project, but am running into a wall when it comes to some more complicated uses of std::async. 我正在努力在项目中实现多线程,但是当涉及到std :: async的一些更复杂的用法时,我会遇到麻烦。 I want to call a member function on a templated object and pass in an argument as a parameter, but I can't get it to work when the template holds a shared pointer. 我想在模板对象上调用成员函数并将参数作为参数传递,但是当模板包含共享指针时,我无法使其工作。

It's pretty simple to use std::async on member functions, and even templated member functions. 在成员函数,甚至模板成员函数上使用std :: async非常简单。 I've seen plenty of answers around stack overflow for this specific usage. 对于这种特定用法,我已经在堆栈溢出周围看到了很多答案。 I've even run some test cases myself: 我甚至亲自运行过一些测试用例:

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

This example compiles perfectly fine in gcc 7.4.0 and returns 42 as expected. 此示例在gcc 7.4.0中完全可以正常编译,并按预期返回42。

My problem comes in when I use shared_ptr in the template. 我在模板中使用shared_ptr时出现了问题。 Using the same Foo and Bar classes from above: 从上面使用相同的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;
}

I get this error when compiling g++ -pthread test.cpp -o test 编译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> (*)())>’

I thought this maybe was because the reference & wasn't working in the proper order with all those angle brackets for the templates, so I tried using some parentheses: 我认为这可能是因为引用&不能在模板的所有尖括号中以正确的顺序使用,所以我尝试使用一些括号:

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

Which results in a shorter error which I also don't understand. 这导致了一个较短的错误,我也不明白。

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

I am confused why the shared pointers all of a sudden make a difference, and I'm guessing it has to do with type deduction? 我感到困惑,为什么共享指针突然有所作为,而我猜想它与类型推导有关? Any help is appreciated. 任何帮助表示赞赏。

EDIT 编辑

Thanks to those that responded, here is the solution. 感谢那些做出回应的人,这是解决方案。 The parentheses are not required, and some shared_ptrs were missing. 不需要括号,并且缺少一些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;
}

There are some issues, I think that using a lambda might help you clarify what is going on: 有一些问题,我认为使用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;
}

You have to pass to the set_data a shared_ptr to Foo . 您必须将一个shared_ptr传递给set_dataFoo Secondly, the set_data is not const-qualified, so you need a mutable lambda. 其次, set_data不是const限定的,因此您需要一个可变的lambda。 Lastly, the future, when returning though get() , will give you a shared_ptr to Bar so you need the operator -> . 最后,将来通过get()返回时,将为Bar提供一个shared_ptr ,因此您需要操作符-> You can make the code more efficient moving Foo2 and Bar inside the lambda, but I am trying to keep the answer simple, in particular because I do not know if you want, in your use case to re-use Foo2 and Bar , but you can consider moving inside the lambda. 您可以使代码更高效的移动Foo2Bar的拉姆达里面,但我想保持的回答简单,特别是因为我,如果你想在你的使用情况,重新使用不知道Foo2Bar ,但你可以考虑在lambda内部移动。

Regarding your specific code, the following is compiling in g++ 9.1 with C++14, see https://godbolt.org/z/DFZLtb 关于您的特定代码,以下内容是在带有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;
}

You need to provide a shared_ptr<Bar> as argument and not a Bar and you need to remove the parenthesis around Foo<std::shared_ptr<Bar>>::set_data . 您需要提供shared_ptr<Bar>作为参数而不是Bar并且需要删除Foo<std::shared_ptr<Bar>>::set_data

You just have some typos in your code, in first shared_ptr example you pass shared_ptr<Foo> instead of raw ptr Foo* to your function. 您的代码中只有一些拼写错误,在第一个shared_ptr示例中,您将shared_ptr<Foo>而不是原始的ptr Foo*传递给函数。 In the second example first argument Foo* is correct, but second one is Bar instead of shared_ptr<Bar> . 在第二个示例中,第一个参数Foo*是正确的,但是第二个参数是Bar而不是shared_ptr<Bar> Here you have the working example: 这里有工作示例:

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 <future>

TEST(xxx, yyy) {
    Foo<std::shared_ptr<Bar> > foo;
    auto bar = std::make_shared<Bar>();
    bar->data = 42;
    auto futureResult = std::async(std::launch::async,
        &Foo<std::shared_ptr<Bar> >::set_data, &foo, bar);
    std::cout << futureResult.get()->data << std::endl;
}

As a side note, if you need to run async operation on some data inside your Foo class, better provide the interface that executes this async operation inside your class and returns the future. 附带说明一下,如果您需要对Foo类内部的某些数据运行异步操作,则最好提供在类内部执行此异步操作并返回未来的接口。

std::future<T> runAsyncOper(const T& data);

Your first example with the shared pointer doesn't pass a shared pointer to std::async as a last parameter, it passes a pointer to function (you didn't add the parentheses) 第一个使用共享指针的示例没有将共享指针传递给std :: async作为最后一个参数,而是将指针传递给函数(您未添加括号)

int main()
{
    /**
    * Works :)
    */
    Foo<std::shared_ptr<Bar>> foo2;

    auto br = std::make_shared<Bar>();

    auto fut2 = std::async(std::launch::async, &Foo<std::shared_ptr<Bar>>::set_data, &foo2, br);

    fut2.wait();
    std::cout << fut2.get()->data << std::endl;

    return 0;
}

Problem is that you passed wrong types of arguments to std::async and used incorrectly std::make_shared . 问题是您将错误的参数类型传递给std::async并且使用了错误的std::make_shared

Minimal modification to your code: 对代码的最小修改:

  auto foo2 = std::make_shared<Foo<std::shared_ptr<Bar>>>();
  auto bar = 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;

https://wandbox.org/permlink/3YXG56ahFKrZs8GB https://wandbox.org/permlink/3YXG56ahFKrZs8GB

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM