从现代C ++ 11函数转换为原始函数指针

时间:2016-09-26 23:47:32

标签: c++ c++11 function-pointers

假设我有以下功能界面:

void giveme(void (*p)());

该函数只接受一个指向函数的指针,没有返回类型和参数。

我想知道是否存在一种方式(而不更改接口)将类方法作为该函数的参数传递。

我会试着通过一个例子更好地解释一下。我有一节课,比如:

class Foo {
 public:
  template<typename T>
  void bar();
};

我想传递bar<T>(该类的可寻址实例)作为函数giveme的参数。

我想用对象绑定方法,并获取函数目标。

类似的东西:

int main(int argc, char *argv[]) {
  Foo foo;
  std::function<void()> f = std::bind(&Foo::bar<int>, &foo);

  giveme(f.target<void()>());

  return 0;
}

它编译,但显然不起作用,因为来自here

  

TargetType应与目标类型匹配,以便typeid(TargetType)==target_type()。否则,该函数始终返回 null 指针。

那么,如果存在,有什么方法可以实现它?

3 个答案:

答案 0 :(得分:5)

这是一个(非常糟糕的)想法:

Foo * foo_ptr;  // maybe thread_local

void foo_call()
{
    foo_ptr->bar<int>();
}

int main()
{
    Foo foo;
    foo_ptr = &foo;
    give_me(&foo_call);
}

它不漂亮,但你的情况也不好。

答案 1 :(得分:1)

我只知道一种方式,这是一个糟糕的主意,不要这样做。

typedef void (*void_fn)();
struct stateful_void_fn_data = {
    void_fn raw;
    std::function<void()> actual;
    std::atomic_bool in_use;
}
// a global array to hold your function bindings and such
extern stateful_void_fn_data stateful_functions[5];
// N stateless functions that defer to the correct global state
template<int n> void void_fn_impl() {stateful_functions[n].actual();}
extern stateful_void_fn_data stateful_functions[5] = 
    {{void_fn_impl<0>}, {void_fn_impl<1>}, {void_fn_impl<2>}, {void_fn_impl<3>}, {void_fn_impl<4>}};
// function to register a stateful and get a stateless back
void_fn allocate_void_fn(std::function<void()>&& f) {
   for(int i=0; i<5; i++) {
       if(stateful_functions[i].in_use.compare_exchange_weak(false, true)) {
            stateful_functions[i].actual = std::move(f);
            return stateful_functions[i].raw;
        }
   }
   throw std::runtime_error("ran out of stateful functions :(");
}
// function to unregister
void free_void_fn(void_fn f) {
    if (f == nullptr) return;
    for(int i=0; i<5; i++) {
        if (stateful_functions[i].raw == f) {
             stateful_functions[i].in_use = false;
             return;
        }
     }
   throw std::runtime_error("unknown void function");
}

基本上,我生成5个void()函数(void_fn_impl<N>),并且每个函数调用存储在五个全局数组槽(stateful_functions[i].actual)之一中的函数。然后,allocate_void_fn将在全局数组中存储任何std::function<void()>,并向您发送调用该数组中该条目的void()。此函数本身是无状态的,因为我们已将所有状态存储在全局数组中。 free_void_fnin_use仅用于使函数可重用。

当然,因为RAII很好:

class hidden_state_void_fn {
    void_fn raw;
public:
    hidden_state_void_fn(std::function<void()>&& f) 
         :raw(allocate_void_fn(std::move(f)) {}
    hidden_state_void_fn(const hidden_state_void_fn&& r) {
         raw = r.raw;
         r.raw = nullptr;
    }
    hidden_state_void_fn& operator=(const hidden_state_void_fn&& r)  {
         free_void_fn(raw);
         raw = r.raw;
         r.raw = nullptr;
    }
    ~hidden_state_void_fn() {free_void_fn(raw);}
    operator void_fn() {return raw;}
    operator()() {raw();}
};

答案 2 :(得分:0)

std::map<int,std::function<void()>> tasks;

template<int n>
struct task_wrapper{
  static void f(){ if (tasks.count(n)) tasks[n](); }
  task_wrapper(std::function<void()> fin){ tasks[n]=fin; }
  ~task_wrapper(){ tasks.erase(n); }
  static std::shared_ptr< void(*)() > make(std::function<void()> fin){
    auto self=std::make_shared<task_wrapper>(fin);
    return { &f, fin };
  }
};

A task_wrapper<N>::make(func)返回一个指向无状态函数指针的共享指针,该指针将调用有状态func

我们可以使用常用技术创建签名shared_ptr<void(*)()>(*)()的K函数指针数组。然后我们可以有一个shared_ptr<void(*)()> register_func( std::function<void()> )

要查找空白,我们可以进行线性搜索,也可以构建空白表。这可能看起来像传统的分配/免费“堆”,或空白的范围树,或其他什么。

另一种方法是在运行中逐字创建并保存DLL,然后加载它并调用符号。这可以通过hacks(具有这样的DLL和已知的偏移来修改,复制和写入,然后加载和运行)或通过运送C ++编译器(或其他编译器)和代码(!)来完成。