SIP4 中的共享指针和构建(是:SWIG/python 中的动态转换?)
所以我正在研究 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_ptr
s rather than raw pointers? If it helps, all of my classes subclassenable_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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
为了(部分)回答我自己的问题,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_ptr
s (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.