我正在尝试将std::function
与std::bind
结合使用,但我遇到了一些问题。
这有效:
#include <functional>
#include <iostream>
void print() {
std::cout << 2;
}
int main() {
std::function<void ()> foo = print;
(*foo.target<void (*)()>())(); //prints 3
}
这会在main
的第二行崩溃:
#include <functional>
#include <iostream>
void print (int i) {
std::cout << i;
}
int main() {
std::function<void ()> foo = std::bind (print, 2);
(*foo.target<void (*)()>())();
}
我真的持有std::function<void ()>
并且需要能够返回该功能;不只是打电话给它。我希望用法是这样的:
#include <functional>
#include <iostream>
void print (int i) {
std::cout << i;
}
int main() {
Container c (std::bind (print, 2));
//I would expect the original
c.func() (3); //prints 3
if (c.func() == print) /* this is what I'm mostly getting at */
}
有没有办法让原始函数返回它,或者替代?它也与返回类型有冲突,因为void (*)()
非常匹配绑定签名。
答案 0 :(得分:24)
这是不可能的。 std::function
存在的全部原因是函数指针可怕地吸吮,并且永远不应该被任何人使用,除了注定了地狱的燃烧标准 C互操作的注定灵魂之外,因为他们无法处理状态函数。
在一般情况下,std::function<void()>
无法转换为void(*)()
。这在第一个示例中起作用的唯一原因是因为发生原来是void(*)()
。
答案 1 :(得分:12)
这可以使用一点模板元编程来实现。我最近在编写围绕OpenGL GLUT的通用C ++包装器时使用了它(它依赖于回调函数指针)。方法:
在C++11 on GCC 4.8下测试。
#include <unistd.h>
#include <thread>
#include <chrono>
#include <mutex>
#include <functional>
#include <iostream>
#include <cmath>
template <const size_t _UniqueId, typename _Res, typename... _ArgTypes>
struct fun_ptr_helper
{
public:
typedef std::function<_Res(_ArgTypes...)> function_type;
static void bind(function_type&& f)
{ instance().fn_.swap(f); }
static void bind(const function_type& f)
{ instance().fn_=f; }
static _Res invoke(_ArgTypes... args)
{ return instance().fn_(args...); }
typedef decltype(&fun_ptr_helper::invoke) pointer_type;
static pointer_type ptr()
{ return &invoke; }
private:
static fun_ptr_helper& instance()
{
static fun_ptr_helper inst_;
return inst_;
}
fun_ptr_helper() {}
function_type fn_;
};
template <const size_t _UniqueId, typename _Res, typename... _ArgTypes>
typename fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::pointer_type
get_fn_ptr(const std::function<_Res(_ArgTypes...)>& f)
{
fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::bind(f);
return fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::ptr();
}
template<typename T>
std::function<typename std::enable_if<std::is_function<T>::value, T>::type>
make_function(T *t)
{
return {t};
}
int main()
{
std::cout << (void*)get_fn_ptr<0>(make_function(::sin))<<std::endl;
return 0;
}
答案 2 :(得分:7)
您无法从std::function
中获取函数指针,因为甚至可能没有。它可以是成员函数指针,也可以是实现operator()
的对象。
答案 3 :(得分:0)
这是不可能的一般,但大多数 C API 都有一个“上下文”指针,您可以与 C 函数指针一起传递。所以对于互操作,你可以用这样的东西包装它(假设 API 首先传递这个“上下文”参数):
template <class R, class... Args>
struct CFunctionPointer
{
std::function<R(Args...)> func;
static R callback(void* context, Args... args)
{
const CFunctionPointer* unpackedThis = reinterpret_cast<const CFunctionPointer*>(context);
return unpackedThis->func(std::forward<Args>(args)...);
}
};
然后会像这样调用:
auto callable = CFunctionPointer<void, const uint8_t*, const uint8_t*>{ [](const uint8_t* begin, const uint8_t* end) { std::cout << "Hello world\n"; } };
cfunc(..., &callable, &callable.callback);
遗憾地将参数类型复制了两次。