鉴于这组文件:

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]; }
};

foo.cpp:
#include "foo.h"

foo.i(尝试 1):
%module foo

%{
#include "foo.h"
%}

%include "foo.h"

%template(intFoo) Foo<int>;

%extend Foo{
    T0& __getitem__(int id) { return ((T0 *)m)[id]; }
}

设置.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"],
      )

测试.py:
from foo import intFoo

a = intFoo(10,20,30)
print(dir(a))
a.info()
print(a[2])

我构建了运行的扩展:
python setup.py build_ext --force -i

但是当我尝试运行 test.py 时,我会得到:
TypeError: 'foo.intFoo' object does not support indexing
extend 中的 foo.i 语句是在任何其他 SO 相关线程上建议的答案,这意味着我在这里错误地使用了它。谁能解释一下如何解决这个问题,以便当我运行 test.py 时能够成功使用 [] 运算符?

另一种尝试:
  • 尝试 2:
    %module foo
    
    %{
    #include "foo.h"
    %}
    
    %include "foo.h"
    
    %template(intFoo) Foo<int>;
    
    %extend intFoo{
        T0& __getitem__(int id) { return ((T0 *)m)[id]; }
    }
    

    抛出这个错误 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>;
    

    抛出这个错误 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
    

    发生这种情况是因为您使用 %extend 添加的方法并不是您将它们添加到的类的真正成员。要在此上下文中访问 m,我们需要使用 $self->m 来引用它。 SWIG 将为我们使用适当的变量 replace $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>
    

    即使您添加了 __getitem__ ,使用 f[n] 进行索引仍然不起作用。发生这种情况是因为 Python 运算符重载中的纯 C-API 类的工作方式不同。您已经成功添加了__getitem__方法,但是Python正在builtin type's slots(特别是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>;
    

    所以现在我们可以做你想做的:

    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>
    

    (实际上您不必再将其称为 __getitem__,因为该函数已在插槽中注册,因此应该可以在没有 operator[] 的情况下调用 %extend,例如)

    最后,您可能希望将返回类型更改为 const T0& ,或者编写一个 Python 类型来更好地代理非常量 int 引用的对象。

    10-05 20:58
    查看更多