diff --git a/src/Converters.cxx b/src/Converters.cxx index 4a338d02..653eb430 100644 --- a/src/Converters.cxx +++ b/src/Converters.cxx @@ -2606,7 +2606,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. @@ -2653,8 +2653,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 @@ -2759,7 +2762,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; @@ -2791,7 +2794,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 e6a81883..5667b44f 100644 --- a/src/DeclareConverters.h +++ b/src/DeclareConverters.h @@ -399,13 +399,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; }