I have a compile problem with multiple inhertance combined with trampolines. The next code explains the problem:
#include <pybind11/pybind11.h>
#include <memory>
namespace py = pybind11;
// classes
class A {
public:
virtual int fA() const = 0;
};
class B : public A, public std::enable_shared_from_this< B > {
public:
int fA() const override {return 1;}
virtual int fB() const {return 2;}
};
// trampolines
class PyA : public A {
public:
using A::A;
int fA() const override {
PYBIND11_OVERLOAD_PURE(int, A, fA);
}
};
class PyB : public B {
public:
using B::B;
int fA() const override {
PYBIND11_OVERLOAD(int, B, fA);
}
int fB() const override {
PYBIND11_OVERLOAD(int, B, fB);
}
};
// bindings
void Bind(py::module_& m)
{
py::class_<A, PyA>(m, "A" )
.def( py::init<>() )
.def( "fA", &A::fA );
// py::class_<B, PyB, std::enable_shared_from_this< B > >(m, "B")
// py::class_<B, PyB, A, std::enable_shared_from_this< B > >(m, "B", py::multiple_inheritance())
// py::class_<B, PyB>(m, "B", py::multiple_inheritance())
py::class_<B, PyB>(m, "B")
.def( py::init<>() )
.def( "fA", &B::fA )
.def( "fB", &B::fB );
}
Shortly,
- class A has a pure virtual method - so needs a tranpoline (PyA).
- class B inherits from A, has virtual methods - so need a trampoline (PyB).
- class B also inherits from std::enable_shared_from_this - so I have a multiple inheritance
- Whatever bind statement I do for class B - compiler complains.
The next is output from c++17:
1>------ Build started: Project: AWB, Configuration: Debug x64 ------
1>Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27045 for x64
1>Copyright (C) Microsoft Corporation. All rights reserved.
1>
1>cl /c /IE:\Projects\AWB\pybind11\include /ID:\Python38\include /Zi /W1 /WX- /diagnostics:classic /Od /Ob0 /D _WINDLL /D _UNICODE /D UNICODE /D WIN32 /D _WINDOWS /Gm- /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Zc:inline /std:c++17 /Fo"AWB.dir\Debug\\" /Fd"AWB.dir\Debug\vc141.pdb" /Gd /TP /errorReport:prompt /bigobj Source.cpp
1>
1>Source.cpp
1>E:\Projects\AWB\pybind11\include\pybind11/pybind11.h(1512): error C2664: 'std::unique_ptr<B,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': cannot convert argument 1 from 'std::shared_ptr<_Ty>' to 'std::nullptr_t'
1> with
1> [
1> _Ty=B
1> ]
1>E:\Projects\AWB\pybind11\include\pybind11/pybind11.h(1507): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>E:\Projects\AWB\pybind11\include\pybind11/pybind11.h(1549): note: see reference to function template instantiation 'void pybind11::class_<B,PyB>::init_holder<B>(pybind11::detail::instance *,pybind11::detail::value_and_holder &,const std::unique_ptr<B,std::default_delete<_Ty>> *,const std::enable_shared_from_this<_Ty> *)' being compiled
1> with
1> [
1> _Ty=B
1> ]
1>E:\Projects\AWB\pybind11\include\pybind11/pybind11.h(1555): note: see reference to function template instantiation 'void pybind11::class_<B,PyB>::init_holder<B>(pybind11::detail::instance *,pybind11::detail::value_and_holder &,const std::unique_ptr<B,std::default_delete<_Ty>> *,const std::enable_shared_from_this<_Ty> *)' being compiled
1> with
1> [
1> _Ty=B
1> ]
1>E:\Projects\AWB\pybind11\include\pybind11/pybind11.h(1549): note: while compiling class template member function 'void pybind11::class_<B,PyB>::init_instance(pybind11::detail::instance *,const void *)'
1>E:\Projects\AWB\pybind11\include\pybind11/pybind11.h(1284): note: see reference to function template instantiation 'void pybind11::class_<B,PyB>::init_instance(pybind11::detail::instance *,const void *)' being compiled
1>Source.cpp(50): note: see reference to class template instantiation 'pybind11::class_<B,PyB>' being compiled
1>e:\projects\awb\pybind11\include\pybind11\cast.h(1638): note: see reference to class template instantiation 'pybind11::detail::descr<8>' being compiled
1>e:\projects\awb\pybind11\include\pybind11\cast.h(1637): note: see reference to class template instantiation 'pybind11::detail::descr<3>' being compiled
1>e:\projects\awb\pybind11\include\pybind11\cast.h(1636): note: see reference to class template instantiation 'pybind11::detail::descr<5>' being compiled
1>e:\projects\awb\pybind11\include\pybind11\cast.h(1177): note: see reference to class template instantiation 'pybind11::detail::descr<7>' being compiled
1>Done building project "AWB.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
If I try with another simple class (C) instead of std::enable_shared_from_this
all goes fine. So the problem might be in a propper formulatiopn at line py:class_<B, PyB, ? >...
or possibly somewhere else...
What am I doing wrong?
Thanks
You nailed the issue. Per pybind's documentation, if you don't specify any holder for a class, the default is
std::unique_ptr
which, as far as I understand, is not compatible withstd::enable_shared_from_this
.Therefore, using
py:class_<B, PyB, std::shared_ptr<B>>
should fix your compilation issue. I have tried this solution and it works on my box.