Home > Software engineering >  How to pass a std::function callback to a function requiring a typedef of a pointer to a function
How to pass a std::function callback to a function requiring a typedef of a pointer to a function

Time:02-18

I've got a C library that takes a function pointer to register commands. I want to use this in my C application. I've tried to use std::function in combination with std::bind to create a C compatible function pointer that will call my member function inside a class. When trying to pass the std::function, I get an compilation error.

// The way the C library typedef's the function
typedef int (*console_cmd_func_t)(int argc, char **argv);

// Function to register the callback needs a struct
struct {
    console_cmd_func_t func;
} console_cmd_t;


void console_cmd_register(const console_cmd_t *cmd) {
    // Register the command
}

// In my C   class
typedef std::function<int(int argc, char **argv)> ConsoleFunction;
ConsoleFunction fn = std::bind(&MyClass::consoleCommandHandler, this, std::placeholders::_1, std::placeholders::_2);

const esp_console_cmd_t runCommand = {
    .func = fn
};
console_cmd_register(&runCommand);

However, this results in the following error:

cannot convert 'ConsoleFunction' {aka 'std::function<int(int, char**)>'} to 'console_cmd_func_t' {aka 'int (*)(int, char**)'} in initialization

Obviously its not the same definition. If I try to correct that however:

typedef std::function<console_cmd_func_t> ConsoleFunction;

I get the following error:

variable 'ConsoleFunction fn' has initializer but incomplete type

How can I successfully register the command?

CodePudding user response:

struct {
    console_cmd_func_t func;
} console_cmd_t;


void console_cmd_register(const console_cmd_t *cmd) {
    // Register the command
}

Your C program is ill-formed. I'm going to assume that console_cmd_t isn't actually an instance of an unnamed struct as is depicted in the quoted code, but is rather a typedef name:

typedef struct {
    console_cmd_func_t func;
} console_cmd_t;

How can I successfully register the command?

By using the types that the functions expect. They don't expect a std::function, so you may not use std::function. There's also no way to register a non-static member function, nor a capturing lambda.

A working example (assuming the correction noted above):

int my_callback(int, char **);
console_cmd_t my_struct {
    .func = my_callback,
};
console_cmd_register(&my_struct);

In order to call a non-static member function, you would typically pass a pointer to the class as an argument into the callback. If the C API doesn't allow passing user defined arguments, then the only option is to use global state. Example:

static MyClass gobal_instance{};

int my_callback(int argc, char **argv)
{
    gobal_instance.consoleCommandHandler(argc, argv);
}

To avoid global state, you need to re-design the C library.

  • Related