python - Cython 中的继承和 std::shared_ptr

标签 python c++ inheritance cython shared-ptr

假设我在 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 仍然存在)。

问题是,wrapperstd::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/

    相关文章:

    python - 有没有办法全局覆盖请求的超时设置?

    python如何附加到zip存档中的文件

    c++ - 通过重载运算符 C++ 比较嵌套内部类

    python - 如何在 Keras 中获取图层的权重?

    c++ - 当 Qt Slot 位于通过 std::async 创建的线程上时,它不会被调用

    C++ 析构函数和函数调用顺序

    c++ - C++ 中 operator= 的奇怪行为

    c++ - 嵌套类设计 C++ virtual

    c++ - CStatic 自定义控件

    Python - 计算数据框中另一列为空的列中的值数