如何合法地将函数指针转换为方法指针?
Posted
技术标签:
【中文标题】如何合法地将函数指针转换为方法指针?【英文标题】:How to legally cast function pointer to method pointer? 【发布时间】:2020-04-29 14:09:30 【问题描述】:我正在寻找 std::mem_fn
的反面:将 函数指针 转换为 成员指针(例如,对于给定的类,void(*)(C*)
到 void(C::*)()
C)。
背景
我正在使用第 3 方库(例如 lib1.h)为另一个第 3 方库(lib2.h)创建绑定。
lib1.h 中的一些函数接收指向接受Value
参数(也在lib1.h 中定义)的方法的方法指针。另一方面,lib2.h 类不包含此类方法,因此我必须通过 lambda 函数手动进行包装:
/* lib1.h (can't touch this) */
class Value;
class Property;
template <typename C>
struct ObjectWrap
using Method = void(C::*)(Value);
static Property declare(std::string name, Method method);
;
/* lib2.h (can't touch this) */
struct Person
void greet(std::string name);
;
/* bindings.cpp */
std::string value_to_std_string(Value v);
Property declarePersonGreet()
return ObjectWrap<Person>::declare("greet",
/* ERROR */ [](Person* p, Value v)
p->greet(value_to_std_string(v));
);
我相当有信心我没有滥用 lib1.h 的 API(不幸的是,通过派生 lib2.h 的类来实现这些方法并非如此一个选项)。因此,我觉得转换为方法指针是唯一的解决方案。
有没有任何合法的方式这样做?如果可能,我想避免未定义的行为。
【问题讨论】:
更好地定义Value
和 Property
和 declare
需要公开。见这里:godbolt.org/z/5dPZzp
您的前提是错误的 - mem_fn
不会将成员指针转换为函数指针,而是将其包装在可调用对象中。
几乎听起来你想要 C++ 中的扩展方法。有一种模仿 C++ 中扩展方法的笨拙方法,但我建议不要在实际代码中使用该技术。 ***.com/a/57081233/4641116
【参考方案1】:
不,你不能做这样的演员。即使你能得到一个void(Person::*)(Value)
,你也不能使用它,因为Person
没有这样的方法。如果 lib1 需要一个带有成员函数 void(C::)(Value)
的类型 C
,那么就没有办法为这种类型 C
提供相应的方法。你可以为Person
写一个包装器:
struct Wrapper
Person p;
void greet(Value v)
p.greet(value_to_std_string(v));
;
Property declarePersonGreet()
return ObjectWrap<Wrapper>::declare("greet",&Wrapper::greet);
如果您有许多类似于Person
的类,您可以将包装器设为模板:
template <typename T>
struct Wrapper
T p;
void greet(Value v)
p.greet(value_to_std_string(v));
;
...可能还对要在包装对象上调用的成员函数和要用于转换参数的函数进行参数化。
【讨论】:
以上是关于如何合法地将函数指针转换为方法指针?的主要内容,如果未能解决你的问题,请参考以下文章
调用旧版 C API 时,如何在现代 C++ 中正确地将指向结构的指针转换为指向其他结构的指针?
C 语言一级指针 易犯错误 模型 ( 判定指针合法性 | 数组越界 | 不断修改指针变量值 | 函数中将栈内存数组返回 | 函数间接赋值形参操作 | 指针取值与自增操作 )