0

I would like to have the following class setup in a program:

  • A class that implements a buffer. This buffer, when full, would spawn a thread that makes a callback to handle what to do with the full buffer.
  • A class that includes a buffer object. Implements the callback function.

I'm having some trouble spawning the std::thread that runs the callback. It seems like I'm getting its parameters wrong, but I can't figure it out.

The minimal reproducible example:

#include <thread>

class MyClass;

class CallbackClass
{
    public:

        void (MyClass::*callback)();
        std::thread a_thread;

        void setCallback(void (MyClass::*cb)())
        {
            callback = cb;
        }

        void writeCall()
        {
            a_thread = std::thread(callback); // error here
        }
};

class MyClass
{
    public:

        CallbackClass callbackobject;

        MyClass()
        {
            callbackobject.setCallback(&MyClass::bufferWriter);
        }

        void bufferWriter(){}
};

int main(){}

The compiler error I get:

error: no matching function for call to ‘std::thread::_Invoker<std::tuple<void (MyClass::*)()> >::_M_invoke(std::thread::_Invoker<std::tuple<void (MyClass::*)()> >::_Indices)’
  operator()()

on this line:

a_thread = std::thread(callback); // error here
dvilela
  • 1,200
  • 12
  • 29
  • 1
    Was this error attached to any particular line of code? – Useless Apr 01 '20 at 16:40
  • @Useless Yes, I've marked it with a comment. – dvilela Apr 01 '20 at 16:41
  • 6
    "callback" is not a callable object. "callback" is a class method. How do you expect `std::thread` to know which object's callback method to invoke? That's your problem. `callback` needs a `Base` object whose method it will invoke. – Sam Varshavchik Apr 01 '20 at 16:41
  • 2
    I've highlighted it a bit for future viewers. – Useless Apr 01 '20 at 16:43
  • Does this answer your question? [Start thread with member function](https://stackoverflow.com/questions/10673585/start-thread-with-member-function) – Daniel Langr Apr 01 '20 at 16:47
  • 1
    Unrelated: This code generates lots of warnings. Some may be important, like `‘class Base’ has virtual functions and accessible non-virtual destructor`. You should turn on more warnings when compiling and try to fix them all. – Ted Lyngmo Apr 01 '20 at 16:50
  • @TedLyngmo Yes, thanks. That problem is related to stripping too much code for the minimal reproducible example, but I actually have a virtual destructor in Base. – dvilela Apr 01 '20 at 16:53
  • I actually answered a similar question yesterday, and could probably answer this one as well, but this is not a "minimal reproducible example", unlike what you state. Shorten it to ~5 lines, should help you find the issue yourself (probably https://en.cppreference.com/w/cpp/named_req/Callable) – NadavS Apr 01 '20 at 16:54
  • @SamVarshavchik You mean that I should store a reference to a Base object as a CallbackBuffer member so I can later invoke Base::bufferWriter? Wouldn't that create a circular dependence? – dvilela Apr 01 '20 at 17:10
  • @NadavS I know it's too much code, but believe me, I've tried to reproduce the error with less, but as soon as I remove a couple more things, it starts compiling even with the error line intact. I wrote the example from scratch, not stripping the actual code, as you may think. – dvilela Apr 01 '20 at 17:17
  • 1
    The only thing I think is that keyword `template` is not necessary to reproduce this issue. – NadavS Apr 01 '20 at 17:19
  • @NadavS Thank you. I've simplified a little more. – dvilela Apr 01 '20 at 17:30
  • 1
    @SamVarshavchik -- `callback` **is** a callable object. A callable type is either a function object type or a pointer to member (and, yes, "pointer to member" includes pointers to member data), and a callable object is an object of a callable type. [func.def] Nevertheless, the problem is, as you say, that for a pointer-to-member the next argument has to be a pointer or reference to an object that the pointer-to-member can be applied to. – Pete Becker Apr 01 '20 at 17:49
  • What "circular dependence" are you referring to? C++ is not Java. – Sam Varshavchik Apr 01 '20 at 17:57
  • @SamVarshavchik Ok, the problem seems solved by storing a pointer to a Base object. Would you like to create an answer so I can vote it? – dvilela Apr 01 '20 at 18:01

1 Answers1

2
void (MyClass::*callback)();

This is a pointer to a class method.

a_thread = std::thread(callback);

A class method is not a function that can be called by itself. The class method requires an object for which it gets invoked. You need to store, or obtain a pointer to a MyClass object, from somewhere. For example, you can pass a 2nd parameter to `setCallback:

void setCallback(void (MyClass::*cb)(), MyClass *ptr)

and then stash it away, somewhere, then use it to invoke the class method. Typically, this would be something like:

a_thread = std::thread(callback, ptr);
Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148