给定这组文件:
foo.h中:
#pragma once
#include <stdio.h>
template <class T0> class Foo {
public:
T0 m[3];
Foo(const T0 &a, const T0 &b, const T0 &c) {
m[0] = a;
m[1] = b;
m[2] = c;
}
void info() { printf("%d %d %d\n", m[0], m[1], m[2]); }
// T0 &operator[](int id) { return ((T0 *)m)[id]; }
};
Run Code Online (Sandbox Code Playgroud)
Foo.cpp中:
#include "foo.h"
Run Code Online (Sandbox Code Playgroud)
foo.i(Attempt1):
%module foo
%{
#include "foo.h"
%}
%include "foo.h"
%template(intFoo) Foo<int>;
%extend Foo{
T0& __getitem__(int id) { return ((T0 *)m)[id]; }
}
Run Code Online (Sandbox Code Playgroud)
setup.py:
import os
import sys
from setuptools import setup, Extension
foo_module = Extension('_foo',
sources=[
'foo.i',
'foo.cpp'
],
swig_opts=['-c++', '-py3', '-builtin'],
include_dirs=['.']
)
setup(name='foo',
version='0.1',
platforms=['Windows', 'Linux'],
ext_modules=[foo_module],
py_modules=["foo"],
)
Run Code Online (Sandbox Code Playgroud)
test.py:
from foo import intFoo
a = intFoo(10,20,30)
print(dir(a))
a.info()
print(a[2])
Run Code Online (Sandbox Code Playgroud)
我构建了扩展运行:
python setup.py build_ext --force -i
Run Code Online (Sandbox Code Playgroud)
但是当我尝试运行test.py时,我会得到:
TypeError: 'foo.intFoo' object does not support indexing
Run Code Online (Sandbox Code Playgroud)
声明extend中foo.i是答案上的任何其他SO线程相关的建议,这意味着我使用它错误地在这里.任何人都可以解释如何解决这个问题,这样当我运行时test.py能够[]成功使用运算符吗?
另一种尝试:
ATTEMPT2:
%module foo
%{
#include "foo.h"
%}
%include "foo.h"
%template(intFoo) Foo<int>;
%extend intFoo{
T0& __getitem__(int id) { return ((T0 *)m)[id]; }
}
Run Code Online (Sandbox Code Playgroud)
引发此错误 TypeError: 'foo.intFoo' object does not support indexing
Attempt3
%module foo
%{
#include "foo.h"
%}
%include "foo.h"
%extend Foo{
T0& __getitem__(int id) { return ((T0 *)m)[id]; }
}
%template(intFoo) Foo<int>;
Run Code Online (Sandbox Code Playgroud)
引发此错误 foo_wrap.cpp(3808): error C2065: 'm': undeclared identifier
(在这个例子中,我正在使用你的第一个版本的foo.i)
首先,%extend您需要在%template指令之前指定才能产生任何效果.
一旦我们修复了,我们现在从您的%extend代码中获得编译器错误:
foo_wrap.cpp: In function 'int& Foo_Sl_int_Sg____getitem__(Foo<int>*, int)':
foo_wrap.cpp:3705:85: error: 'm' was not declared in this scope
Run Code Online (Sandbox Code Playgroud)
发生这种情况是因为您添加的方法%extend实际上并不是您要添加它们的类的成员.要m在此上下文中访问,我们需要改为引用它$self->m.SWIG将为我们替换$self适当的变量.(值得快速查看生成的代码以了解其工作原理)
调试字体图或扩展名时,一个有用的提示是搜索您在SWIG生成的输出中编写的代码 - 如果它不在那里,那么它就不会按您的想法应用.
因此,一旦我们修复了关于m未被声明的错误,我们就会遇到另一个问题,因为你编译了-builtin:
In [1]: import foo
In [2]: f=foo.intFoo(1,2,3)
In [3]: f[0]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-3-e71eec16918d> in <module>()
----> 1 f[0]
TypeError: 'intFoo' object does not support indexing
In [4]: f.__getitem__(0)
Out[4]: <Swig Object of type 'int *' at 0xa8807d40>
Run Code Online (Sandbox Code Playgroud)
即使你已添加__getitem__,索引f[n]仍然无法正常工作.这种情况正在发生,因为Python中的纯C-API类操作符重载不能以相同的方式工作.您已__getitem__成功添加了一个方法,但Python正在查看内置类型的插槽(特别是mp_subscript)以获取执行操作的方法.所以我们也需要解决这个问题.完成后,一个工作foo.i看起来像:
%module foo
%{
#include "foo.h"
%}
%feature("python:slot", "mp_subscript", functype="binaryfunc") Foo::__getitem__;
%include "foo.h"
%extend Foo{
T0& __getitem__(int id) { return ((T0 *)$self->m)[id]; }
}
%template(intFoo) Foo<int>;
Run Code Online (Sandbox Code Playgroud)
所以现在我们可以做你想做的事:
In [1]: import foo
In [2]: f=foo.intFoo(1,2,3)
In [3]: f[0]
Out[3]: <Swig Object of type 'int *' at 0xb4024100>
Run Code Online (Sandbox Code Playgroud)
(你实际上并没有叫它__getitem__任何更多,因为函数获取插槽登记的,应该可以调用operator[]没有%extend在所有的情况下)
最后,您可能希望将返回类型更改为const T0&,或者将Python类型写入代理对象以更好地进行非const int引用.