[英]Convert from modern C++11 function to raw function pointer
Let's suppose I have the following function interface: 假设我具有以下功能接口:
void giveme(void (*p)());
That function simply accepts a pointer to a function with no return type and argument. 该函数仅接受指向没有返回类型和参数的函数的指针 。
I'm wondering if exists a way ( without change the interface ) to pass a class method as parameter of that function. 我想知道是否存在一种方法( 不更改接口 )将类方法作为该函数的参数传递。
I'll try to explain better with an example. 我将尝试用一个例子更好地解释。 I have a class, like:
我有一堂课,例如:
class Foo {
public:
template<typename T>
void bar();
};
I want to pass bar<T>
(of an addressable instance of the class) as parameter of the function giveme
. 我想将
bar<T>
(该类的可寻址实例的实例)作为函数giveme
参数giveme
。
I thought to bind the method with an object, and obtain the function target. 我想将方法与对象绑定 ,并获得功能目标。
Something like: 就像是:
int main(int argc, char *argv[]) {
Foo foo;
std::function<void()> f = std::bind(&Foo::bar<int>, &foo);
giveme(f.target<void()>());
return 0;
}
It compiles, but obviously does not work because, from here : 它可以编译,但显然不起作用,因为从这里开始 :
TargetType
shall match the target type, so thattypeid(TargetType)==target_type()
.TargetType
应匹配目标类型,以便typeid(TargetType)==target_type()
。 Otherwise, the function always returns a null pointer.否则,函数将始终返回空指针。
So, if exists, what is a way to achieve it? 那么,如果存在,有什么方法可以实现呢?
Here's one (very bad) idea: 这是一个(非常糟糕的)想法:
Foo * foo_ptr; // maybe thread_local
void foo_call()
{
foo_ptr->bar<int>();
}
int main()
{
Foo foo;
foo_ptr = &foo;
give_me(&foo_call);
}
It's not pretty, but neither is your situation. 它不漂亮,但您的情况也不是。
There's only one way I know of, and it's a terrible idea, and don't do this. 我只知道一种方法,这是一个糟糕的主意,不要这样做。
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");
}
Basically, I generate 5 void()
functions ( void_fn_impl<N>
), and each calls a function stored in one of the five a global array slots ( stateful_functions[i].actual
). 基本上,我生成5个
void()
函数( void_fn_impl<N>
),每个函数调用存储在五个全局数组插槽之一中的函数( stateful_functions[i].actual
)。 Then, allocate_void_fn
will store any std::function<void()>
in the global array, and hand you the void()
that calls that entry in the array. 然后,
allocate_void_fn
将把任何std::function<void()>
在全局数组中,并向您提供在数组中调用该条目的void()
。 This function itself is stateless, because we've stored all the state in the global array. 该函数本身是无状态的,因为我们已将所有状态存储在全局数组中。
free_void_fn
and in_use
exist solely to make the functions reusable. free_void_fn
和in_use
仅用于使这些函数可重用。
And of course, because RAII is good: 当然,因为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();}
};
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)
return a shared pointer to a stateless function pointer that will call the stateful func
. task_wrapper<N>::make(func)
返回一个共享的指针,该指针指向将调用有状态func
的无状态函数指针。
We can use the the usual techniques to create an array of K function pointers of signature shared_ptr<void(*)()>(*)()
. 我们可以使用通常的技术来创建签名为
shared_ptr<void(*)()>(*)()
的K个函数指针的数组。 Then we can have a shared_ptr<void(*)()> register_func( std::function<void()> )
. 然后我们可以有一个
shared_ptr<void(*)()> register_func( std::function<void()> )
。
To find blanks, we can either do a linear search, or we could build a table of blanks. 要查找空白,我们可以进行线性搜索,也可以构建空白表。 This could look like a traditional allocation/free "heap", or a range-tree of blanks, or whatever.
这看起来像是传统的分配/免费的“堆”,或者是空白的范围树,等等。
Another approach would be to literally create and save a DLL on the fly then load it and call the symbol. 另一种方法是即时创建并保存DLL,然后加载它并调用该符号。 This could be done via hacks (have such a DLL and a known offset to modify, copy and write, then load and run) or by shipping a C++ compiler (or other compiler) with your code (!).
这可以通过黑客(具有这样的DLL和已知的偏移量来进行修改,复制和写入,然后加载并运行)或通过将C ++编译器(或其他编译器)与您的代码一起交付(!)来完成。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.