1

反復可能な C++ クラスを実装しようとしています。これまでのところ、私はこれを書いています:

class XYByFrameIterator {
 public:
  XYByFrameIterator(vector<xy>& precalc) :_precalc(precalc), _current(precalc.begin()), _end(precalc.end()) {}

  XYByFrameIterator* __iter__() { cout << "__iter__" << endl; return this;}

  xy& next() throw (Stop_Iteration) {
    if (_current == _end)
      throw Stop_Iteration();
    xy& ret = *_current;
    _current++;
    return ret; 
  }

 private:
  vector<xy>& _precalc;
  vector<xy>::iterator _current;
  vector<xy>::iterator _end;
};

カスタム C++Stop_Iteration例外を PythonStopIteration例外に変換するために、これを swig インターフェイス ファイルに追加しました。

%typemap(throws) Stop_Iteration %{
  PyErr_SetNone(PyExc_StopIteration);
  SWIG_fail;
%}

残念ながら、これは一部のケースでしか機能しません。たとえば、次の python コードは、期待どおりに x/y 値を出力します。

it = fa.xyByFrameIterator(43)
for xy in it:
    print(xy.x)
    print(xy.y)

しかし、ループ内でイテレータを直接インスタンス化すると、クラッシュします:

for xy in fa.xyByFrameIterator(43):
    print(xy.x)
    print(xy.y)

出力:

__iter__
44.2233009338
5.83165979385
segmentation fault

アップデート:

この回答を読んだ後、解決策を見つけました。__iter__メソッドをPythonに渡した後、メソッドに何か問題があったと思います。__iter__ここで、swig インターフェイス ファイルを介して Python コードに直接挿入します。次のようになります。

%typemap(throws) Stop_Iteration %{
  PyErr_SetNone(PyExc_StopIteration);
  SWIG_fail;
%}
%extend XYByFrameIterator
{
%insert("python") %{
    def __iter__(self):
        return self
%}
}

そして私のC ++コード:

class XYByFrameIterator {
 public:
  XYByFrameIterator(vector<xy>& precalc) :_precalc(precalc), _current(precalc.begin()), _end(precalc.end()) {}
  xy& next() throw (Stop_Iteration) {
    if (_current == _end)
      throw Stop_Iteration();
    xy& ret = *_current;
    _current++;
    return ret; 
  }

 private:
  vector<xy>& _precalc;
  vector<xy>::iterator _current;
  vector<xy>::iterator _end;
};

これは静かにうまく機能しますが、swig インターフェイス ファイル内の各反復子クラスのコードがない (または少ない) ソリューションが望ましいと思います。

4

0 に答える 0