从方法指针动态创建通用函数指针,推导出返回值和参数
我有这个辅助类,用于调用需要静态 C 函数的代码的成员方法。这个特定的“版本”与 Windows LPTHREADROUTINE 回调兼容,采用 DWORD (class::method) (void *) 函数作为参数,如下调用:
CreateThread(NULL, 0, runThreadFunction<SomeClass>, makeThreadInfo(&myClass, &SomeClass::ThreadFunction, NULL), 0, NULL);
我希望使整个事情变得通用,我知道可以使用新的 C++11 标准来完成,但我无法实现。
#pragma once
#include <stdafx.h>
template <typename C>
struct ThreadInfo
{
// we have an object
C* obj;
// and that object has a function that takes void* and returns DWORD, and so is suitable for a threadproc (except for it being a member function)
DWORD (C::* function)(void*);
// and we have any amount of extra data that we might need.
void* data;
// default copy c-tor, d-tor and operator= are fine
ThreadInfo(C* o, DWORD (C::*func)(void*), void* d) : obj(o), function(func), data(d)
{
}
};
template <typename C>
DWORD WINAPI RunThreadFunction(void* data)
{
shared_ptr<ThreadInfo<C> > ti((ThreadInfo<C>*)data);
//ThreadInfo<C>* ti = (ThreadInfo<C>*) data;
return ((ti->obj)->*(ti->function))(ti->data);
}
template <typename C>
void* MakeThreadInfo(C* o, DWORD (C::* f)(void*), void* d)
{
return (void*)new ThreadInfo<C>(o, f, d);
}
我尝试将 MakeThreadInfo 函数的接口更改为如下所示:
template <typename C, typename R, typename... P>
void* MakeThreadInfo(C* o, std::function<R(P&...)> f, void* d)
这似乎是可行的方法,但我无法将此值传递给上游。
这就是我想要得到的:
给定一个带有方法 MyMethod 的类 MyClass,以及 变量 返回类型的回调和一个或多个不同类型 的参数(最后一个这是一个void *userData
),我怎样才能用尽可能少的样板,将一些东西传递给回调并让它依次调用MyClass::MyMethod。
举例说明:
typedef bool (*Callback1)(void *userData);
typedef int (*Callback2)(bool param, void *userData);
void TheirLibrary::Function1(Callback1 callback, void *userData);
void TheirLibrary::Function2(Callback2 callback, void *userData);
class MyClass
{
bool MyMethod1(void *userData);
int MyMethod2(bool someParam, void *userData);
void DoSomething()
{
Function1(CreateGenericCPointer(&MyClass::MyMethod1), &MyClass);
Function2(CreateGenericCPointer(&MyClass::MyMethod2), &MyClass);
}
}
CreateGenericCPointer
的有效实现是什么?
I have this helper class that I use to call member methods for code that's expecting static C functions. This particular "version" is compatible with Windows LPTHREADROUTINE callbacks, taking a DWORD (class::method) (void *)
function as a parameter, called like this:
CreateThread(NULL, 0, runThreadFunction<SomeClass>, makeThreadInfo(&myClass, &SomeClass::ThreadFunction, NULL), 0, NULL);
I wish to make the entire thing generic, and I know it can be done with the new C++11 standard, but I'm unable to pull it off.
#pragma once
#include <stdafx.h>
template <typename C>
struct ThreadInfo
{
// we have an object
C* obj;
// and that object has a function that takes void* and returns DWORD, and so is suitable for a threadproc (except for it being a member function)
DWORD (C::* function)(void*);
// and we have any amount of extra data that we might need.
void* data;
// default copy c-tor, d-tor and operator= are fine
ThreadInfo(C* o, DWORD (C::*func)(void*), void* d) : obj(o), function(func), data(d)
{
}
};
template <typename C>
DWORD WINAPI RunThreadFunction(void* data)
{
shared_ptr<ThreadInfo<C> > ti((ThreadInfo<C>*)data);
//ThreadInfo<C>* ti = (ThreadInfo<C>*) data;
return ((ti->obj)->*(ti->function))(ti->data);
}
template <typename C>
void* MakeThreadInfo(C* o, DWORD (C::* f)(void*), void* d)
{
return (void*)new ThreadInfo<C>(o, f, d);
}
I've tried changing the interface of the MakeThreadInfo function to something like this:
template <typename C, typename R, typename... P>
void* MakeThreadInfo(C* o, std::function<R(P&...)> f, void* d)
Which would seem to be the way to go, but I was unable to then pass this value upstream.
Here's what I want to get at:
Given a class MyClass with a method MyMethod, and a callback of variable return type and one or more parameters of varying types (the last of which is a void *userData
), how can I, with as little boilerplating as possible, pass something to the callback and have it in turn call MyClass::MyMethod.
To illustrate:
typedef bool (*Callback1)(void *userData);
typedef int (*Callback2)(bool param, void *userData);
void TheirLibrary::Function1(Callback1 callback, void *userData);
void TheirLibrary::Function2(Callback2 callback, void *userData);
class MyClass
{
bool MyMethod1(void *userData);
int MyMethod2(bool someParam, void *userData);
void DoSomething()
{
Function1(CreateGenericCPointer(&MyClass::MyMethod1), &MyClass);
Function2(CreateGenericCPointer(&MyClass::MyMethod2), &MyClass);
}
}
What's a valid implementation of CreateGenericCPointer
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我也有同样的问题。我想将“指向类成员方法的指针”转换为“指向函数的指针”,因为 Windows API 回调都是“指向函数的指针”。我使用 X86-64 编译器,并且只有一种调用约定。当使用“指向类成员方法的指针”时,传递给函数的第一个参数是“this”,因此当您想将其转换为“指向函数的指针”时,您必须考虑将“this”传递给您的函数。 “指向类成员方法的指针”作为第一个参数,然后传递其他参数。我的方法通过在虚拟地址空间中动态创建可执行二进制代码来实现此目的。请记住,它适用于最多具有 3 个参数的函数,而且它不支持浮点参数作为函数的输入参数。 (因为浮点参数是通过 XMM0、XMM1、XMM2、XMM3 寄存器传输的)。
I had the same problem. I wanted to cast "pointer to a class member method" to "pointer to a function" as Windows API callbacks are all "pointer to a function". I work with X86-64 compiler and there is only one calling conventions. When using "pointer to a class member method", the first parameter passed to the function is "this", so when you want to cast it to a "pointer to a function" you have to consider "this" to be passed to your "pointer to a class member method" as the first argument and then the other arguments are passed. My method does this by creating executable binary code in virtual address space on the fly. Remember that it works with functions with at most 3 parameters and also it does not support floating-point arguments as the input arguments of functions. (Because floating-point arguments are transferred by XMM0, XMM1, XMM2, XMM3 registers).
我并不完全清楚您正在寻找什么级别的通用性,但这也许会让您开始:
请注意,因为
myClass
是一个std::shared_ptr<>
并通过值捕获,即使myClass
在线程完成执行之前超出范围,底层SomeClass
的生命周期也会正确终止(只要RunThreadFunction
最终被调用)。编辑:这是另一种方法(未经测试,可能是语法错误):
It's not entirely clear to me what level of genericity you're looking for, but maybe this will get you started:
Note that because
myClass
is astd::shared_ptr<>
and is captured by value, the underlyingSomeClass
's lifetime will terminate properly even ifmyClass
goes out of scope before the thread is finished executing (as long asRunThreadFunction
is eventually called).EDIT: Here's another approach (untested, may be syntax errors):
看看这是否是您想要的。您仍然必须指定返回类型,但(在我看来)它很好地指定为保存
static
包装函数的struct
的模板参数。如果您需要更高程度的灵活性TTst
,您仍然可以改进它 - 我不确定您希望如何定义要调用的成员函数,因此我将其签名保留为callback的。
编辑:修改了
Bar01
的参数 - 我没有注意到它接受 2 个参数作为Bar00
...只是为了澄清,您需要定义一个模板化Call< /code> 函数用于具有相同数量参数的所有
回调
。See if this is what you want. You still have to specify return type, but it's nicely (in my opinion) specified as a template parameter to
struct
that holdstatic
wrapper functions. You can still improve it if you need higher degree of flexibility forTTst
- I'm not sure how you want to define member functions to be called, so I kept their signature ascallback
's.EDIT: modified arguments to
Bar01
- I didn't notice it accepts 2 arguments asBar00
... Just to clarify, you need to define one templatedCall
function for allCallback
's that have the same number of arguments.编辑:这并不完全是OP所需要的。 OP 需要一个通用版本。
为什么不完全使用 std::function 呢?
看起来
runStdFunction 将像馅饼一样简单,
我正在使用 typedef std::function;为了简单起见,使用 voidFunction 。
这个想法很简单,您所做的就是传递 std::functions,然后调用它们。
将所有与成员函数/等之间的转换留给 std::bind。
当然,您的返回类型不是 void,但这只是一个小细节。
EDIT: This is not quite what the OP needs. The OP needs a generic version of this.
Why not use a std::function all the way through?
It would look like
runStdFunction will then be as simple as pie
I am using
typedef std::function<void(void)> voidFunction
for simplicity.The idea is simple, all you are doing is passing std::functions through and then calling them.
Leave all of the converting to/from member functions/etc to std::bind.
Of course your return type is not void, but that's a minor detail.