diff --git a/src/Converters.cxx b/src/Converters.cxx index 6a7f36bd..579d1fc3 100644 --- a/src/Converters.cxx +++ b/src/Converters.cxx @@ -2642,7 +2642,7 @@ static PyMethodDef gWrapperCacheEraserMethodDef = { }; static void* PyFunction_AsCPointer(PyObject* pyobject, - const std::string& rettype, const std::string& signature) + const std::string& rettype, const std::string& signature, bool allowCppInstance) { // Convert a bound C++ function pointer or callable python object to a C-style // function pointer. The former is direct, the latter involves a JIT-ed wrapper. @@ -2699,8 +2699,11 @@ static void* PyFunction_AsCPointer(PyObject* pyobject, return fptr; } - if (PyCallable_Check(pyobject)) { + if (PyCallable_Check(pyobject) && (allowCppInstance || !CPPInstance_Check(pyobject))) { // generic python callable: create a C++ wrapper function + // Sometimes we don't want to take this branch if the object is a C++ + // instance, because C++ doesn't allow converting functor objects to + // function pointers, but only to std::function. void* wpraddress = nullptr; // re-use existing wrapper if possible @@ -2805,7 +2808,7 @@ bool CPyCppyy::FunctionPointerConverter::SetArg( } // normal case, get a function pointer - void* fptr = PyFunction_AsCPointer(pyobject, fRetType, fSignature); + void* fptr = PyFunction_AsCPointer(pyobject, fRetType, fSignature, fAllowCppInstance); if (fptr) { SetLifeLine(ctxt->fPyContext, pyobject, (intptr_t)this); para.fValue.fVoidp = fptr; @@ -2837,7 +2840,7 @@ bool CPyCppyy::FunctionPointerConverter::ToMemory( } // normal case, get a function pointer - void* fptr = PyFunction_AsCPointer(pyobject, fRetType, fSignature); + void* fptr = PyFunction_AsCPointer(pyobject, fRetType, fSignature, fAllowCppInstance); if (fptr) { SetLifeLine(ctxt, pyobject, (intptr_t)address); *((void**)address) = fptr; diff --git a/src/DeclareConverters.h b/src/DeclareConverters.h index 8cac6f2a..1de04d51 100644 --- a/src/DeclareConverters.h +++ b/src/DeclareConverters.h @@ -418,13 +418,16 @@ class FunctionPointerConverter : public Converter { protected: std::string fRetType; std::string fSignature; + bool fAllowCppInstance = false; }; // std::function class StdFunctionConverter : public FunctionPointerConverter { public: StdFunctionConverter(Converter* cnv, const std::string& ret, const std::string& sig) : - FunctionPointerConverter(ret, sig), fConverter(cnv) {} + FunctionPointerConverter(ret, sig), fConverter(cnv) { + fAllowCppInstance = true; + } StdFunctionConverter(const StdFunctionConverter&) = delete; StdFunctionConverter& operator=(const StdFunctionConverter&) = delete; virtual ~StdFunctionConverter() { delete fConverter; }