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.