2

I create an object of type T in a template class.

template <class T>
class worker
{
public:
    worker() { obj = new T(app_cfg);}
    ~worker() { if (obj) { delete obj; obj = nullptr; }}

    void start();

private:
    T * obj = nullptr;
    std::atomic<bool> is_work_{ false };
    std::thread thread_{};

};

The object has a check() method. I want to run a check() method on a thread. And I do it like this:

template <class T>
void worker<T>::start() {
    is_work_ = true;
    thread_ = std::thread(&T::check, obj, is_work_);
}

After that an error occurs:
Error C2661 no overloaded function taking 3 arguments

I think that the problem is in the thread launch syntax.
How to correctly specify the parameters for launch?

pipetka
  • 43
  • 3
  • 4
    Can you make this a [mcve]? – Retired Ninja Jul 21 '22 at 11:12
  • 1
    and the complete error message please – 463035818_is_not_an_ai Jul 21 '22 at 11:12
  • 1
    Side-note: This is a [Rule of 3](https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming))/5 violation. The moment you write a custom destructor, you must define a copy constructor and copy assignment operator, and ideally you should define a move constructor and move assignment operator as well (though you can avoid a lot of duplication by relying on [the copy-and-swap idiom](https://stackoverflow.com/a/3279550/364696)). As written, if someone inadvertently copies your class, you'll have double-free bugs. – ShadowRanger Jul 21 '22 at 11:15
  • 2
    I dont get the point of closing as duplicate before it is even possible to know what the issue is. There is nothing apparently wrong in the code here, but it is missing crucial information. Maybe the answer is in one of the dupes, maybe not – 463035818_is_not_an_ai Jul 21 '22 at 11:16
  • Have a look at lambas (for easy capture of this) and std::async (instead of std::thread) – Pepijn Kramer Jul 21 '22 at 11:18
  • 1
    @463035818_is_not_a_number I agree Anoop is sometimes a bit too quick. – Pepijn Kramer Jul 21 '22 at 11:18
  • You can initialize like this: ```auto thr = std::thread([](Param1 p1, Param2 p2, Param3 p3){ ... func(); ... });``` but different instances would need to pass the new function or just use static function or it will try access deleted object's method. – huseyin tugrul buyukisik Jul 21 '22 at 11:43
  • @huseyintugrulbuyukisik there is no need to use a lambda to call a method, `std::thread` supports this directly – Alan Birtles Jul 21 '22 at 12:00
  • 2
    My guess of a duplicate would be https://stackoverflow.com/questions/34078208/passing-object-by-reference-to-stdthread-in-c11 https://godbolt.org/z/8W7sfs6GY – Alan Birtles Jul 21 '22 at 12:08
  • @AlanBirtles that depends on the `check` method signature. If it takes references, then yes, but otherwise (if OP is ok with passing a copy) the problem is rather with using the atomic boolean, which doesn't have a copy constructor – The Dreams Wind Jul 21 '22 at 12:20
  • @TheDreamsWind like I said, "my guess" – Alan Birtles Jul 21 '22 at 12:22
  • 1
    @TheDreamsWind, This is the best answer. Of course atomic boolean doesn't have a copy constructor! If I change the type from atomic_boolean to boolean - everything works! – pipetka Jul 21 '22 at 12:33

1 Answers1

0

Possible solution :

#include <future>       // https://en.cppreference.com/w/cpp/thread/future
#include <iostream>

template <class T>
class worker_t
{
public:
    void start()
    {
        // I prefer using std::async over std::thread
        // it has better abstraction and automatic synchonization on future destructor
        // future also allows you to return values and errors (exceptions) from the 
        // background thread to the calling thread.
        // The [&]{...} is a lambda function, easy to call 
        // member functions this way (without the need for
        // complicated member function pointers)
        m_future = std::async(std::launch::async, [&] { obj.check(); });
    }

private:
    T obj; // no need for a pointer just create a member
    std::future<void> m_future;
};

class object_t
{
public:
    void check()
    {
        std::cout << "Hello World!";
    }
};

int main()
{

    worker_t<object_t> worker;
    worker.start();

    // destructor of worker_t will synchronize with its member future
    // ensuring the thread also did its work. 
    // before exiting the program

    return 0;
}
Pepijn Kramer
  • 9,356
  • 2
  • 8
  • 19
  • I'm not saying you are wrong, but the alternative with futures is not what OP was asking for. The question is narrowed down to simply `How to correctly specify the parameters for launch?` and that is what was supposed to be answered. Also, if you suggest using alternative API, it's better to provide rationale why `std::thread` should be avoided and why `std::future` does the job better in this particular case. – The Dreams Wind Jul 21 '22 at 12:18
  • The lambda solution will also work for std::thread – Pepijn Kramer Jul 21 '22 at 12:38