2017-06-15 5 views
1

コンテナのようなオブジェクト(具体的には、PythonのC APIからタプル)へのレガシーC APIがあります。これは素敵なC++ 14 API 、私はイテレータを使用することができます。これを実装するにはどうすればいいですか?C++で従来のC APIをラップしてイテレータをサポートする

ここにいくつかの詳細があります。私たちは、変更することはできません、次の既存のC APIを持っています。

Py_ssize_t PyTuple_GET_SIZE(PyObject *p); 
PyObject* PyTuple_GET_ITEM(PyObject *p, Py_ssize_t pos); 
void PyTuple_SET_ITEM(PyObject *p, Py_ssize_t pos, PyObject *o) 

私たちは、あなたがタプルの要素の読み取り/書き込みイテレータへのアクセスを取得することを可能にするクラスを作成します。

前方読み取り専用イテレータはあまりにも定義するのが難しくありません。ここに私が持っているものがあります:

class PyTuple { 
private: 
    PyObject* tuple; 

public: 
    PyTuple(PyObject* tuple) : tuple(tuple) {} 

    class iterator { 
    // iterator traits 
    PyObject* tuple; 
    Py_ssize_t index; 
    public: 
    iterator(PyObject *tuple, Py_ssize_t index) : tuple(tuple), index(index) {} 
    iterator& operator++() { index++; return *this; } 
    iterator operator++(int) { auto r = *this; ++(*this); return r; } 
    bool operator==(iterator other) const { return tuple == other.tuple && index == other.index; } 
    bool operator!=(iterator other) const { return !(*this == other); } 
    PyObject* operator*() { return PyTuple_GET_ITEM(tuple, index); } 
    // iterator traits 
    using difference_type = Py_ssize_t; 
    using value_type = PyObject*; 
    using pointer = PyObject**; 
    using reference = PyObject*&; 
    using iterator_category = std::forward_iterator_tag; 
    }; 

    iterator begin() { 
    return iterator(tuple, 0); 
    } 

    iterator end() { 
    return iterator(tuple, PyTuple_GET_SIZE(tuple)); 
    } 
} 

しかし、私はどのように書き込みをサポートするかについてはあまりよく分かりません。どういうわけか*it = pyobj_ptrを作っておかなければなりません。従来は、タイプをPyObject*& operator*()に変更することで(これは左辺値を与えるようになりましたが)、タプル「書き込み」がPyTuple_SET_ITEMを通過する必要があるため、これを行うことはできません。私はこのケースを解決するのにoperator=を使うことができると聞いたことがありますが、普遍的なリファレンス(Why no emplacement iterators in C++11 or C++14?)またはプロキシクラス(What is Proxy Class in C++)を使うべきかどうかはわかりません。

+0

例:

は基本的に、あなたはあなたのような何かを与えることをoperator*()をしたいhttps://stackoverflow.com/a/25938871/315052あなたはのためのベースとしてのstd ::イテレータを使用することを検討すべきである – jxh

+0

あなたイテレータ。 –

+0

std :: iteratorはC++で推奨されていません17 https://stackoverflow.com/questions/37031805/preparation-for-stditerator-being-deprecatedこれ以上使用しないと思います! –

答えて

3

あなたが探しているのは、基本的にプロキシリファレンスです。あなたはPyObject*に逆参照したくないので、それ自体があなたにPyObject*を与えることができるものに逆参照したいと思います。これは、vector<bool>のような型のイテレータの振る舞いに似ています。

class PyObjectProxy { 
public: 
    // constructors, etc. 

    // read access 
    operator PyObject*() const { return PyTuple_GET_ITEM(tuple, index); } 

    // write access 
    void operator=(PyObject* o) { 
     PyTuple_SET_ITEM(tuple, index, o); // I'm guessing here 
    } 
private: 
    PyObject* tuple; 
    Py_ssize_t index; 
}; 
+0

ありがとう、それは物事をうまく説明します!私はいくつか質問があります:(1)emplacementイテレータに関するSOのリンクでは、C++標準ではプロキシを使用しない特定のイテレータが必要であると言われています。なぜこの制限が課せられたのですか? (2)OutputIteratorに気付きましたが、イディオムは '*'演算子を 'return * this'と定義することです。 IIUC、これは読み込みでは機能しませんか? –

+0

別の言い方をすれば、プロキシオブジェクトはイテレータオブジェクト(フィールドワイズ)と変わって見えますが、どちらの場合も同じものを使用することはできないと思いますか? –

+0

@ EdwardZ.Yang私はいずれかの質問、またはそれらがこの問題にどのように関係しているか理解していません。さまざまな問題を解決するには、異なるタイプを使用する方がよいでしょう。 – Barry

関連する問題