我正在尝试使用c
编写的库进行交互,该库使用这种熟悉的模式:
void some_c_handler(void(*func)(void*), void* data);
现在,我想为此函数编写一个C++
包装器,如下所示:
void my_new_cpp_handler(std::function<void()>&& func)
{
void (*p)() = foo(func);
void* data = bar(func);
some_c_handler(p, data);
}
some_c_handler
和my_new_cpp_handler
都解决了同样的问题;他们与某个州一起承担某种功能。但后者是首选,因为它从用户抽象了大部分实现细节,并允许简单地传入lambda对象。
因此my_new_cpp_handler
应该使用func
参数,将其转换为函数指针并将其状态传递给data
。
我对std::function
的标准或实施知之甚少,不知道这是否是一个合理的要求。可以foo
和bar
存在吗?
换句话说,我想要的是能够将有状态函数传递给c
回调处理程序,而不必手动实例化我自己的struct
类型来传递它。显然std::function
已经为我们做了这个,所以我希望能够以某种方式将函数指针与状态分开并将其传递给c
样式的处理程序。这可能吗?
答案 0 :(得分:8)
这可能吗?
没有
您可以将C样式的回调包装到std::function<>...
中,编译器将发出代码以提取data
和handler
并调用它。但是,这样做的确切代码将取决于编译器,ABI
和正在使用的标准C ++库。只有std::function
包装器,你才能神奇地重建代码。
此外,任意std::function...
(或lambda)可以包装代码其他而不是调用C风格的处理程序。显而易见的是,应用&#34;神奇地重建&#34;从这样的std::function...
实例中提取C风格处理程序的代码可能无法成功。
P.S。
换句话说,我想要的是能够将有状态函数传递给c回调处理程序,而不必手动实例化我自己的结构类型来传递它。显然
std::function
已经为我们做了这个
为什么不你只是使用std::function
为你做过的事情:
void my_new_cpp_handler(std::function<void()>&& func)
{
func(); // calls some_c_handler(p, data) IFF that is what "func" encodes.
}
答案 1 :(得分:6)
如果您仔细查看此库的文档,您会发现
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库的指针,以及指向&#34; trampoline函数的指针&#34;:
some_c_handler(&cpp_trampoline, reinterpret_cast<void *>(pointer));
蹦床改写了不透明的指针:
void cpp_trampoline(void *pointer)
{
auto real_pointer=reinterpret_cast<std::function< ... >*>(pointer);
// At this point, you have a pointer to the std::function here.
// Do with it as you wish.
这里需要平衡的唯一细节是找出动态分配的函数指针的正确范围,以避免内存泄漏。
答案 2 :(得分:5)
您可以创建一个包装函数,其目的是简单地执行std::function
回调。
void some_c_handler(void(*)(void*), void*) {}
void std_function_caller(void* fn) {
(*static_cast<std::function<void()>*>(fn))();
};
auto make_std_function_caller(std::function<void()>& fn) {
return std::make_pair(std_function_caller, static_cast<void*>(&fn));
}
void my_new_cpp_handler(std::function<void()>&& func) {
const auto p = make_std_function_caller(func);
some_c_handler(p.first, p.second);
}
答案 3 :(得分:-2)
根据this链接,std::function
对象没有可以提供指针原始访问权限的可访问成员。您应该定义一个struct
,它包含一个指向函数指针和对象的指针,以及一个构造函数包装器,它在构造std::struct
之前将指针的地址存储到结构中,所以至于将存储在指针中的地址分配给你的C处理程序的参数。