Pass *this as argument to method invoked by thread

南笙酒味 提交于 2021-01-29 15:58:18

问题


I have a member function which I cannot unit test easily (it listens to sockets etc):

void MyClass::func()
{
    listen();
    send();
}

So I want to template it and then I can pass a mock object in my test:

template<class OBJECT>
void func(OBJECT& obj)
{
    obj.listen();
    obj.send();
}

and then I'd do:

func(*this);

The above compiles when I do a normal function call. However, when I spawn a thread and call it:

std::thread t1(&MyClass::func, this, *this);

I get compiler errors (see below) referring to decltype. Is there a way I can still achieve this?

/opt/gcc-8.2.0/lib/gcc/x86_64-unknown-linux/8.2.0/../../../../include/c++/8.2.0/thread:127:8: note: in instantiation of template class 'std::thread::_Invoker<std::tuple<void (MyClass::*)(MyClass &),
      MyClass *, MyClass> >' requested here
              __make_invoker(std::forward<_Callable>(__f),

However, the following works:

void MyClass::x()
{
    func(*this);
}

std::thread t1(&MyClass::x, this);

回答1:


There are two issue in your code:

First, you cannot pass function templates to the std::thread constructor. You must explicitly specify what specialisation of the function template to use, which in this case, would be &MyClass::func<MyClass>.

Second you are trying to pass a reference as an argument to the constructor of std::thread. When the std::thread constructor is called, the first argument is the function to run concurrently, and the others are the argument to the function. The other arguments are moved and then passed as argument to the function. This is fine if the argument is a pointer or a variable, but causes an issue if the function expects a non-const lvalue as an argument.

You can solve both issues by constructing std::thread with lambdas:

std::thread t1([=]{
    this->func(*this);
});

Conversely, you could use std::ref, a reference wrapper, in the std::thread constructor, and explicitly specify the function template specialisation:

#include<functional>

std::thread t1(&MyClass::func<MyClass>, this, std::ref(*this));

Personally, I much prefer constructing std::threads with lambdas, as it is cleaner and less error prone.



来源:https://stackoverflow.com/questions/61376914/pass-this-as-argument-to-method-invoked-by-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!