Reputation: 14269
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.
Upvotes: 0
Views: 84
Reputation: 473966
consteval
is not a macro; it's not just a textual copy-and-paste. It's a way of decorating a function such that using it outside of constant expression evaluation is a compile error. consteval
functions therefore must follow the rules of constexpr
functions.
Among those rules are that reinterpret_cast
, and any C-style cast that would be equivalent to one, is expressly forbidden. Conversion of a function pointer to one signature to a different signature requires a reinterpret_cast
, even if you're using a C-style cast. So it's not allowed.
You can use a non-constexpr
function call if you want to avoid a macro. But you can't use a compile-time construct for something that cannot be done at compile-time.
Upvotes: 2