I'm trying to write a thin wrapper layer to interface c++ classes from python.
Python itself uses those three signatures to call a c function from py:
typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
typedef PyObject *(*PyCFunctionWithKeywords)(PyObject *, PyObject *, PyObject *);
typedef PyObject *(*PyNoArgsFunction)(PyObject *);
Unfortunately, the PyMethodDef
struct stores a function as PyCFunction
and a flags
member to decide at runtime which function is actually stored/called.
I wrote a function template which takes three PyObject*
s and returns one PyObject*
, essentially a PyCFunctionWithKeywords
, calling the classes member function with either zero, one or two arguments (as the first argument is the instance itself).
template<auto Fn>
PyObject* member_wrapper(PyObject* obj, PyObject* args, PyObject* kwargs)
Fn
is the member function pointer to wrap. Given a macro:
#define PY_WRAP(fn) (PyCFunction)::py::member_wrapper<fn>
I can successfully set the function pointer:
PyCFunction func = PY_WRAP(&MyClass::SomeFunc);
Above compiles as expected. However I've tried using a consteval function instead of a macro:
template<typename T>
consteval PyCFunction make_wrapper(T fn) {
return (PyCFunction)::py::member_wrapper<fn>;
}
PyCFunction func = make_wrapper(&MyClass::SomeFunc);
This however fails with:
error C2440: Cannot convert "PyObject *(__cdecl *)(PyObject *,PyObject *,PyObject *)" to "PyCFunction"
I'm confused why the cast works in the macro but fails in the consteval function.