1

I need to wrap a callback mechanism in a C interface in C++ accepting callables. In the C interface there is a method to set the callback:

void c_set_callback(void(*callback)(void* context), void* context);

Here is my attempt to wrap this with a callable:

template<typename Function>
void set_callback(Function&& function)
{
    c_set_callback
        ([](void* context)
            {
                (*reinterpret_cast<typename std::decay<Function>::type*>(context))();
            }
        , reinterpret_cast<void*>(&function)
        );
}

But I can't figure out the right way of casting the context for the universal reference to "function". With the implementation above I get a segmentation fault when the callable is invoked from within the lambda.

Please see https://onlinegdb.com/r1WeuBz08 for the full code example.

Giovanni Cerretani
  • 1,693
  • 1
  • 16
  • 30
Lorenz Zhao
  • 242
  • 1
  • 11

1 Answers1

1

Although it is legal to cast a lambda with no captures to a C-style function pointer, your lambda scope is limited to the call to c_set_callback.

My approach would be to call once c_set_callback at the very beginning of your program, with a static C function as argument. That function, internally, calls a static std::function<void()>, and then make your set_callback to just change the static std::function<void()>.

Something like

#include <functional>

std::function<void()> local_callback;

extern "C" void callback_wrapper(void *) {
    local_callback();
}

template<typename Function>
void set_callback(Function&& function) {
    local_callback = std::forward<Function>(function);
}

int main() {
    c_set_callback(&callback_wrapper, nullptr);
    // ...
}
Giovanni Cerretani
  • 1,693
  • 1
  • 16
  • 30
  • Ah, sure, thanks for pointing the scope issue out. Well the intention was to wrap the C interface in a stateless C++ class, plus in my use case I actually have to support multiple callbacks (which is not visible from my example). I think I will create another question on SO because the question (and title) is pretty different (and unrelated to the current question) then. Thanks a lot to solve the first step! – Lorenz Zhao Jun 26 '20 at 07:29