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?

3
  • 2
    add static to int myCallback(int x);. This question suffers from XY problem so can't provide better answer. Commented Dec 7, 2021 at 8:16
  • As said by @MarekR, adding static works: godbolt.org/z/hrb3WjeKr Commented Dec 7, 2021 at 8: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. Commented Dec 7, 2021 at 8:28

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

4 Comments

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. ?
@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).
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.
@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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.