SIP4 中的共享指针和构建(是:SWIG/python 中的动态转换?)

发布于 2024-09-08 13:09:04 字数 2372 浏览 1 评论 0原文

所以我正在研究 Python、C++0x 和 SWIG 2.0。我有一个如下所示的标头:

#include <string>
#include <iostream>
#include <memory>
using namespace std;

struct Base {
  virtual string name();
  int foo;
  shared_ptr<Base> mine;
  Base(int);  
  virtual ~Base() {}
  virtual void doit(shared_ptr<Base> b) {
    cout << name() << " doing it to " << b->name() << endl;
    mine = b;
  }
  virtual shared_ptr<Base> getit() {
    return mine;
  }
};

struct Derived : Base {
  virtual string name();
  int bar;
  Derived(int, int);
};

同时,接口文件如下所示:

%module(directors="1") foo
%feature("director");

%include <std_string.i>

%include <std_shared_ptr.i>
%shared_ptr(Base)
%shared_ptr(Derived)

%{
#define SWIG_FILE_WITH_INIT
#include "foo.hpp"
%}

%include "foo.hpp"

我的 Python 会话如下所示:

>>> import foo
>>> b = foo.Base(42)
>>> d = foo.Derived(23,64)
>>> b.doit(d)
Base doing it to Derived 
>>> g = b.getit()
>>> g
<foo.Base; proxy of <Swig Object of type 'std::shared_ptr< Base > *' at 0x7f7bd1391930> >
>>> d
<foo.Derived; proxy of <Swig Object of type 'std::shared_ptr< Derived > *' at 0x7f7bd137ce10> >
>>> d == g
False
>>> d is g
False
>>> d.foo == g.foo
True
>>> d.bar
64
>>> g.bar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Base' object has no attribute 'bar'

我似乎无法弄清楚如何在此处检索“原始”代理对象。我必须为每个基类生成一个函数来执行dynamic_pointer_cast吗?如果是这样,那么用 Python 实现的 Director 子类又如何呢?

我感觉有一个开关或功能可以在这里打开,让 SWIG 进行必要的表查找并生成我想要的对象,但我还没有找到它。

(注意:如果我使用原始指针而不是共享指针,则行为类似,并且我无法弄清楚如何让 SWIG 到 dynamic_cast 这些)

更新

如果这种行为(具体来说,检索从 C++ 容器类派生最多的代理(包含指向基类的指针)在 SWIG 中是不可能的,那么 SIP 或其他 Python 包装器生成器又如何呢?

更新 #2

由于 SIP4 看起来在明智地检索包装对象方面效果更好一些,所以我将再次更改问题。请查看下面我的自我回答,了解有关我当前问题的详细信息。我仍然会接受原始 SWIG 问题的一个很好的答案,因为我总体上更喜欢它,但我的新问题基本上是:

  • 如何合理地处理 shared_ptr 周围的包装器而不是原始的指点?如果有帮助的话,我的所有类都从其通用基类中子类 enable_shared_from_this 并公开适当的函数来获取共享指针。

  • 使用 SIP4 的构建系统(Makefile 生成器或 distutils 扩展)构建我的小示例项目,而无需首先生成和安装共享库或手动编辑生成的 Makefile?

So I'm playing about with Python, C++0x, and SWIG 2.0. I've got a header that looks like this:

#include <string>
#include <iostream>
#include <memory>
using namespace std;

struct Base {
  virtual string name();
  int foo;
  shared_ptr<Base> mine;
  Base(int);  
  virtual ~Base() {}
  virtual void doit(shared_ptr<Base> b) {
    cout << name() << " doing it to " << b->name() << endl;
    mine = b;
  }
  virtual shared_ptr<Base> getit() {
    return mine;
  }
};

struct Derived : Base {
  virtual string name();
  int bar;
  Derived(int, int);
};

Meanwhile, the interface file looks like this:

%module(directors="1") foo
%feature("director");

%include <std_string.i>

%include <std_shared_ptr.i>
%shared_ptr(Base)
%shared_ptr(Derived)

%{
#define SWIG_FILE_WITH_INIT
#include "foo.hpp"
%}

%include "foo.hpp"

My Python session then goes like this:

>>> import foo
>>> b = foo.Base(42)
>>> d = foo.Derived(23,64)
>>> b.doit(d)
Base doing it to Derived 
>>> g = b.getit()
>>> g
<foo.Base; proxy of <Swig Object of type 'std::shared_ptr< Base > *' at 0x7f7bd1391930> >
>>> d
<foo.Derived; proxy of <Swig Object of type 'std::shared_ptr< Derived > *' at 0x7f7bd137ce10> >
>>> d == g
False
>>> d is g
False
>>> d.foo == g.foo
True
>>> d.bar
64
>>> g.bar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Base' object has no attribute 'bar'

I can't seem to figure out how to retrieve the "original" proxy object here. Must I produce a function for each and every base class to perform the dynamic_pointer_cast? And if so, what of Director subclasses implemented in Python?

I get the feeling there's a switch or feature I can turn on here to get SWIG to do the necessary table lookups and produce the object I want, but I haven't found it yet.

(Note: The behavior is similar if I use raw pointers instead of shared pointers, and I can't figure out how to get SWIG to dynamic_cast those either)

Update

If this sort of behavior (specifically, retrieving the most-derived proxy from a C++ container class that holds pointers to the base class) isn't possible in SWIG, then how about SIP or some other wrapper generator for Python?

Update #2

Since SIP4 looks like it works a bit better as far as retrieving the wrapped object sensibly, I'll change the question once again. Check my self answer below for details on my current issues. I'll still accept a good answer for the original SWIG question since I prefer it overall, but my new questions are, basically:

  • How can I deal sanely with wrappers around shared_ptrs rather than raw pointers? If it helps, all of my classes subclass enable_shared_from_this from their generic base classes and expose an appropriate function to get the shared pointer.

  • How can I, using either of SIP4's build systems (Makefile generator or distutils extension), build my little example project without having to first generate and install a shared library or manually edit the generated Makefile?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

墨小墨 2024-09-15 13:09:04

为了(部分)回答我自己的问题,SIP 似乎做了正确的事情,无论是对于 C++“派生”类还是 Python 级子类 - 至少当我使用原始指针时。

看起来我需要弄清楚如何让它与 shared_ptr 一起工作(看起来不像 SWIG 中的 %include 那么容易) 。

另外,两个 SIP 的“构建系统”选项(Makefile 生成器和 distutils 扩展)似乎有点奇怪。他们的手册中的两个示例都“不起作用” - 看起来他们希望很明显您应该在库中编译和安装共享库和头文件/包含您正在尝试的小 Hello World 库的路径包裹。也许我错过了一个“我只想在此处构建并运行这个独立的东西”选项,但即使 python setup.py build_ext --inplace 也会失败,因为它找不到包装的我知道,我已将其放置在当前目录中,这显然是一个令人困惑的地方。

To (partially) answer my own question, SIP appears to do the right thing, both for the C++ "Derived" class as well as for a Python-level subclass — at least, when I use raw pointers.

Looks like I'll need to figure out how to get it to work with shared_ptrs (looks not quite as easy as %include <std_shared_ptr.i> in SWIG).

Also, both of SIPs "build system" options (Makefile generator and distutils extension) seem a little odd. Neither example in their manual "just works" - it looks like they expect it to be obvious that you're supposed to compile and install a shared library and header file in your library/include paths for the little Hello World library you're trying to wrap. Perhaps there's an "I just want to build and run this self-contained thing right here" option that I missed, but even python setup.py build_ext --inplace fails because it can't find the wrapped header that I've placed in the current directory, which is obviously a confusing place for it, I know.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文