1

I have a function that runs a callback:

void run_callback(void(*callback)(uint32_t)) {
    callback(100);
}

This works with static functions,

void global_callback(uint32_t);

int main() {
    run_callback(global_callback);
}

but not with member functions.

class A {
    int x;
  public:
    void callback(uint32_t);
};

int main() {
    A foo;
    run_callback(foo.callback);
}

I work around this with a static wrapper function.

void run_member_callback(void* obj, void(*callback)(void*,uint32_t)) {
    callback(obj, 100);
}

class B {
    int x;
  public:
    static void static_callback(void* obj, uint32_t value) {
        static_cast<B*>(obj)->callback(value);
    }
    void callback(uint32_t);
};

int main() {
    B foo;
    run_member_callback(&foo, foo.static_callback);
}

Is there a simple way to pass a member function as an argument?

edit: I'm trying to avoid STL, and templates aren't an option since my implementation of run_callback is virtual.

rcelyte
  • 11
  • 4
  • Possible duplicate of [What's the difference between a method and a function?](https://stackoverflow.com/questions/155609/whats-the-difference-between-a-method-and-a-function) – Tim Aug 25 '19 at 00:18
  • 1
    That's real close, @Tim , but not quite close enough. Here's another almost-duplicate:[How can I pass a member function where a free function is expected?](https://stackoverflow.com/questions/12662891/how-can-i-pass-a-member-function-where-a-free-function-is-expected) Put them to gether and you get some [Bibbidi Bobbidi Boo](https://www.youtube.com/watch?v=VNKuARjkWEg). – user4581301 Aug 25 '19 at 00:24
  • 1
    Some good general purpose reading on the topic: [Pointers to Member Functions](https://isocpp.org/wiki/faq/pointers-to-members) – user4581301 Aug 25 '19 at 00:26
  • That kind of code could be fragile particularly if you have multiple inheritance. Better to remplace your `void *` with `B *` and reduce the number of cast. And also use pointer to member functions. – Phil1970 Aug 25 '19 at 00:38
  • Is `run_callback` a function that you wrote and can change, or is it from some library or API that you have to use as-is? – Joseph Sible-Reinstate Monica Aug 25 '19 at 00:42
  • Possible duplicate of [Is there a a way to achieve closures in C](https://stackoverflow.com/questions/4393716/is-there-a-a-way-to-achieve-closures-in-c) – ead Aug 26 '19 at 11:07
  • You are trying to create a closure in C, for this to work you will need to generate some code at runtime - this is what FFCALL-library will do for you, your workaround is basically the standard way for to achieve the same goal, if the signature of the callback can be changed. – ead Aug 26 '19 at 11:10

1 Answers1

3

You are doing some weird, C-ish things. Use C++ features. I personally would use a template for run_callback and a lambda for passing the member function:

template <class F>
void run_callback(F callback)
{
    callback(100);
}

class A
{
    int x;
  public:
    void callback(uint32_t);
};

int main()
{
    A foo{};
    run_callback([&](uint32_t a) { return foo.callback(a); });
}

If you capture the object by reference take care it outlives the run_callback call. Otherwise capture it by value.


What is a lambda expression in C++11?

bolov
  • 72,283
  • 15
  • 145
  • 224
  • In some case, it might be useful to use `std::function` instead for example if `run_callback` is complex and used with different argument types. – Phil1970 Aug 25 '19 at 00:40
  • 1
    @Phil1970 avoid `std::function` unless you really need the type erasure (like storing functions in a collection). It adds considerable overhead and has a notably performance hit. – bolov Aug 25 '19 at 02:40
  • @bolov That was my concern. – rcelyte Aug 26 '19 at 02:12