0

I have a worker class, which takes a callback function pointer initialization in the constructor. I would like to instantiate the worker in my class, and provide a pointer to a member function as a callback.

The worker class:

class Worker
{
public:
    typedef int (*callFunct)(int);
    Worker(callFunct callback = nullptr);
    ~Worker();

private:
    callFunct m_callback = nullptr;
};

Worker::Worker(callFunct callback) : m_callback(callback)
{
}

and here is my class, where I would like to have Worker instance and a member callback function:

class myClass
{
public:
    myClass();
    ~myClass() = default;

private:
    int myCallback(int x);
    Worker m_worker {&myClass::myCallback};
};

Unfortunately this does not compile:

    error: could not convert '{&myClass::myCallback}' from '<brace-enclosed initializer list>' to 'Worker'

I am aware that when dealing with pointer to a member class I have to provide the instance object as well. But what is the correct way to do in this situation, when I need to have pointer to class member?

Sebastian Green
  • 51
  • 1
  • 1
  • 4
  • 2
    add `static` to `int myCallback(int x);`. This question suffers from [XY problem](https://xyproblem.info/) so can't provide better answer. – Marek R Dec 07 '21 at 08:16
  • As said by @MarekR, adding `static` works: https://godbolt.org/z/hrb3WjeKr – kiner_shah Dec 07 '21 at 08:24
  • BTW, you can use godbolt.org for checking using different compilers, I found clang gave a bit better error description than gcc in this case. – kiner_shah Dec 07 '21 at 08:28

1 Answers1

6

Pointers to non-member functions are not the same as pointers to (non-static) member functions!

The difference is that a (non-static) member function needs an object to be called on, which pointers to non-member function doesn't have.

You can use std::function and lambdas to create the callback:

class Worker
{
public:
    using callFunct = std::function<int(int)>;

    Worker(callFunct callback)
        : m_callback(callback)
    {
    }

private:
    callFunct m_callback;
};

class myClass
{
public:
    myClass()
        : m_worker([this](int x) { return myCallback(x); })
    {
    }

private:
    int myCallback(int x);
    Worker m_worker;
};

Or if the callback doesn't need to acces the myClass object, then make the function static:

class myClass
{
public:
    myClass();

private:
    static int myCallback(int x);
    Worker m_worker {&myClass::myCallback};
};

[As mentioned by others in comments to the question]

Or a plain lambda that does what myClass::myCallback would do.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • How to refactor your example not to use std::function? I would like not to change the `Worker` class and keep the `typedef int (*callFunct)(int);` And, secondly, what do you mean by `Or a plain lambda that does what myClass::myCallback would do.` ? – Sebastian Green Dec 08 '21 at 07:37
  • @SebastianGreen If you want to use pointers to non-member functions, then you need to use either `static` member function, non-member functions (of course), or non-capturing lambdas. You can't use plain member functions without other work (like using extra "user-data" pointer arguments, where a static member function could use the "user-data" pointer as a pointer to the object, and then call the actual member function). – Some programmer dude Dec 08 '21 at 07:42
  • A `static` member is not an option, of course, as it cannot access the non-static members from the class, nor is the non-member functions. Can you provide an example, how to do it with non-capturing lambda? Can we keep the `typedef int (*callFunct)(int);` definition from the `Worker` class? Can we avoid `std::function`, by replacing it, say, with `std::bind'? Thanks. – Sebastian Green Dec 10 '21 at 14:18
  • @SebastianGreen Static function *can* work, if you have some way of passing a "user-data" pointer to it. That pointer could be a pointer to the object, and then the static function could call the correct function using the object. A non-capturing lambda is not going to be possible though, as you still need to capture the object. I only mentioned it because they can be implicitly converted to a pointer to a non-member function. – Some programmer dude Dec 10 '21 at 14:57