I'm looking for the opposite of std::mem_fn
: turning a function pointer into a member pointer (e.g. void(*)(C*)
to void(C::*)()
for a given class C).
I'm using a 3rd party library (say lib1.h) to create bindings for another 3rd party library (lib2.h).
Some functions in lib1.h receive method pointers to methods that accept a Value
argument (also defined in lib1.h). In other hand, lib2.h classes do not contain such methods, so I have to do the wrappings manually through a lambda function:
/* 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));
});
}
I'm fairly confident that I'm not misusing lib1.h's API (and implementing such methods by deriving the classes of lib2.h is unfortunately not an option). Therefore I feel that casting to method pointers is the only solution.
Is there any way of legally doing this? I would like to avoid undefined behavior if possible.
No you cannot do such cast. Even if you could get a void(Person::*)(Value)
, you could not use that because Person
has no such method. If lib1 expects a type C
with a member function void(C::)(Value)
then there is no way around providing such type C
with the corresponding method. You can write a wrapper for 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);
}
If you have many classes similar to Person
you could make the wrapper a template:
template <typename T>
struct Wrapper {
T p;
void greet(Value v) {
p.greet(value_to_std_string(v));
}
};
...possibly also parameterized on the member function to be called on the wrapped object and the function to be used for converting the parameter.