假设我在 file.h
中有以下简单的 C++ 继承示例:
class Base {};
class Derived : public Base {};
然后,以下代码编译;也就是说,我可以分配std::shared_ptr<Derived>
至std::shared_ptr<Base>
:Derived* foo = new Derived();
std::shared_ptr<Derived> shared_foo = std::make_shared<Derived>(*foo);
std::shared_ptr<Base> bar = shared_foo;
假设我已将类型添加到 decl.pxd
:cdef extern from "file.h":
cdef cppclass Base:
pass
cdef cppclass Derived(Base):
pass
然后,我要做的是在 file.pyx
中模仿 Cython 中的上述 C++ 赋值。 :cimport decl
from libcpp.memory cimport make_shared, shared_ptr
def do_stuff():
cdef decl.Derived* foo = new decl.Derived()
cdef shared_ptr[decl.Derived] shared_foo = make_shared[decl.Derived](foo)
cdef shared_ptr[decl.Base] bar = shared_foo
与 C++ 案例不同,现在失败并出现以下错误(使用 Cython 3.0a6):cdef shared_ptr[decl.Base] bar = shared_foo
^
---------------------------------------------------------------
Cannot assign type 'shared_ptr[Derived]' to 'shared_ptr[Base]'
我应该期待这种行为吗?有什么方法可以模仿 C++ 示例对 Cython 的作用吗?编辑:参见。对以下已接受答案的评论,相关功能已添加到 Cython,并且从 3.0a7 版本开始可用。
最佳答案
它应该适用于 Cython>=3.0,因为 @fuglede 做了这个 PR修复下面描述的问题(对于 Cython<3.0 仍然存在)。
问题是,wrapper的 std::shared_ptr
未命中
template <class U> shared_ptr& operator= (const shared_ptr<U>& x) noexcept;
的std::shared_ptr
-类(class)。如果你像这样修补包装器:
cdef extern from "<memory>" namespace "std" nogil:
cdef cppclass shared_ptr[T]:
...
shared_ptr[T]& operator=[Y](const shared_ptr[Y]& ptr)
#shared_ptr[Y](shared_ptr[Y]&) isn't accepted
您的代码将编译。你可能会问,为什么
operator=
而不是构造函数shared_ptr[Y]
需要,因为:...
cdef shared_ptr[decl.Base] bar = shared_foo
看起来构造函数( template <class U> shared_ptr (const shared_ptr<U>& x) noexcept;
)不明确。但这是 Cython 的 C++ 怪癖之一。上面的代码将被翻译成std::shared_ptr<Base> __pyx_v_bar;
...
__pyx_v_bar = __pyx_v_shared_foo;
并不是std::shared_ptr<Base> __pyx_v_bar = __pyx_v_shared_foo;
因此 Cython 将检查 operator=
的存在(对我们来说很幸运,因为 Cython 似乎不支持带有模板的构造函数,但对操作符却支持)。如果你想在没有打补丁的系统上发布你的模块
memory.pxd
你有两个选择:std::shared_ptr
自己正确%%cython
...
cdef extern from *:
"""
template<typename T1, typename T2>
void assign_shared_ptr(std::shared_ptr<T1>& lhs, const std::shared_ptr<T2>& rhs){
lhs = rhs;
}
"""
void assign_shared_ptr[T1, T2](shared_ptr[T1]& lhs, shared_ptr[T2]& rhs)
...
cdef shared_ptr[Derived] shared_foo
# cdef shared_ptr[decl.Base] bar = shared_foo
# must be replaced through:
cdef shared_ptr[Base] bar
assign_shared_ptr(bar, shared_foo)
...
这两种选择都有缺点,因此根据您的情况,您可能更喜欢其中一种。
关于python - Cython 中的继承和 std::shared_ptr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67626270/