如何将std :: function对象传递给带有函数指针的函数?

时间:2016-09-18 20:35:25

标签: c++ c

我正在尝试使用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_handlermy_new_cpp_handler都解决了同样的问题;他们与某个州一起承担某种功能。但后者是首选,因为它从用户抽象了大部分实现细节,并允许简单地传入lambda对象。

因此my_new_cpp_handler应该使用func参数,将其转换为函数指针并将其状态传递给data

我对std::function的标准或实施知之甚少,不知道这是否是一个合理的要求。可以foobar存在吗?

换句话说,我想要的是能够将有状态函数传递给c回调处理程序,而不必手动实例化我自己的struct类型来传递它。显然std::function已经为我们做了这个,所以我希望能够以某种方式将函数指针与状态分开并将其传递给c样式的处理程序。这可能吗?

4 个答案:

答案 0 :(得分:8)

  

这可能吗?

没有

您可以将C样式的回调包装到std::function<>...中,编译器将发出代码以提取datahandler并调用它。但是,这样做的确切代码将取决于编译器,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处理程序的参数。