如何将std :: function对象传递给带有函数指针的函数?
我正在尝试使用c
编写的库,它使用这种熟悉的模式:
void some_c_handler(void(*func)(void*), void* data);
现在,我想为这个函数编写一个C++
包装器,如下所示:
void my_new_cpp_handler(std::function&& func) { void (*p)() = foo(func); void* data = bar(func); some_c_handler(p, data); }
some_c_handler
和my_new_cpp_handler
都解决了同样的问题; 他们与某个州一起承担某种function。 但后者是首选的,因为它从用户抽象出大部分实现细节,并允许简单地传入lambda对象。
所以my_new_cpp_handler
应该获取它给出的func
参数,将其转换为函数指针并将其状态传递给data
。
我不太了解标准,或std::function
的实现,知道这是否是一个合理的请求。 可以和foo
存在吗?
换句话说,我想要的是能够将有状态函数传递给c
回调处理程序,而不必手动实例化我自己的struct
类型以传递它。 显然std::function
已经为我们做了这个,所以我希望能够以某种方式将函数指针与状态分开并将其传递给c
style处理程序。 这可能吗?
这可能吗?
没有。
您可以将C样式的回调包装到std::function<>...
,编译器将发出代码以提取data
和handler
并调用它。 但是,这样做的确切代码将取决于编译器, ABI
和正在使用的标准C ++库。 只有std::function
包装器才能神奇地重建代码。
此外,任意std::function...
(或lambda)可以包装除C调式处理程序之外的代码。 很明显,应用“神奇重建”代码从std::function...
这样一个实例中提取C风格的处理程序std::function...
不可能成功。
PS
换句话说,我想要的是能够将有状态函数传递给ac回调处理程序,而不必手动实例化我自己的结构类型来传递它。 显然
std::function
已经为我们做了这个
那你为什么不用 std::function
已经为你做了什么:
void my_new_cpp_handler(std::function&& func) { func(); // calls some_c_handler(p, data) IFF that is what "func" encodes. }
如果您仔细查看该库的文档,您会发现
void some_c_handler(void(*func)(void*), void* data);
调用func
,传递data
参数。
对于采用回调函数的C库,这是一种非常常见的设计模式。 除了回调函数之外,它们还采用了一个不被库解释的额外的不透明指针,而是盲目地转发到func
。 换句话说,C库调用
func(data);
您可以使用C ++代码中的此函数将普通指针传递给任何类。
这也包括std::function
。
诀窍在于,在大多数情况下,有必要使用new
:
auto *pointer=new std::function< function_type >...
最终结果是一个可以传递给C库的指针,以及一个指向“trampoline函数”的指针:
some_c_handler(&cpp_trampoline, reinterpret_cast(pointer));
蹦床重铸了不透明的指针:
void cpp_trampoline(void *pointer) { auto real_pointer=reinterpret_cast*>(pointer); // At this point, you have a pointer to the std::function here. // Do with it as you wish.
您需要在这里找到的唯一细节是找出动态分配的函数指针的正确范围,以避免内存泄漏。
您可以创建一个包装函数,其目的是简单地执行std::function
回调。
void some_c_handler(void(*)(void*), void*) {} void std_function_caller(void* fn) { (*static_cast*>(fn))(); }; auto make_std_function_caller(std::function& fn) { return std::make_pair(std_function_caller, static_cast(&fn)); } void my_new_cpp_handler(std::function&& func) { const auto p = make_std_function_caller(func); some_c_handler(p.first, p.second); }
根据此链接, std::function
对象没有可以提供对指针的原始访问的可访问成员。 您应该定义一个包含指向函数指针和对象的指针的结构,以及一个构造函数包装器,它在构造std::struct
之前将指针的地址存储到std::struct
,以便分配存储在指针中的地址它指向您的C处理程序的参数。