pybind11,使用 std::enable_shared_from_this 绑定 Trampolines 和多重继承时编译失败
pybind11, compile fails on binding Trampolines and multiple inheritance with std::enable_shared_from_this
我遇到了多重继承结合蹦床的编译问题。下一段代码说明了问题:
#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 );
}
很快,
- class A 有一个纯虚方法 - 所以需要一个 tranpoline (PyA)。
- class B 继承自 A,具有虚方法 - 所以需要一个蹦床 (PyB)。
- class B 也继承自 std::enable_shared_from_this - 所以我有多重继承
- 无论我为 class B 做什么绑定语句 - 编译器都会抱怨。
下一个是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 ==========
如果我尝试使用另一个简单的 class (C) 而不是 std::enable_shared_from_this
一切正常。所以问题可能出在 py:class_<B, PyB, ? >...
行或其他地方的适当公式中......
我做错了什么?
谢谢
你解决了这个问题。根据 pybind's documentation,如果您没有为 class 指定任何持有人,则默认为 std::unique_ptr
,据我所知,它与 std::enable_shared_from_this
不兼容。
因此,使用 py:class_<B, PyB, std::shared_ptr<B>>
应该可以解决您的编译问题。我试过这个解决方案,它适用于我的盒子。
我遇到了多重继承结合蹦床的编译问题。下一段代码说明了问题:
#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 );
}
很快,
- class A 有一个纯虚方法 - 所以需要一个 tranpoline (PyA)。
- class B 继承自 A,具有虚方法 - 所以需要一个蹦床 (PyB)。
- class B 也继承自 std::enable_shared_from_this - 所以我有多重继承
- 无论我为 class B 做什么绑定语句 - 编译器都会抱怨。
下一个是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 ==========
如果我尝试使用另一个简单的 class (C) 而不是 std::enable_shared_from_this
一切正常。所以问题可能出在 py:class_<B, PyB, ? >...
行或其他地方的适当公式中......
我做错了什么?
谢谢
你解决了这个问题。根据 pybind's documentation,如果您没有为 class 指定任何持有人,则默认为 std::unique_ptr
,据我所知,它与 std::enable_shared_from_this
不兼容。
因此,使用 py:class_<B, PyB, std::shared_ptr<B>>
应该可以解决您的编译问题。我试过这个解决方案,它适用于我的盒子。