C ++ 14 — Обертывание устаревшего API C в C ++ с поддержкой итераторов записи

У меня есть устаревший C API к объекту, похожему на контейнер (в частности, Python C API для кортежей), который я хотел бы обернуть в красивый C ++ 14 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*() (так что это дает lvalue), но я не могу сделать это, потому что кортеж «write» должен пройти PyTuple_SET_ITEM, Я слышал, что вы можете использовать operator= чтобы решить это дело, но я не уверен, следует ли мне использовать универсальную ссылку (Почему нет итераторов размещения в C ++ 11 или C ++ 14?) или прокси-класс (Что такое прокси-класс в C ++), и я не совсем уверен, как должен выглядеть код.

1

Решение

То, что вы ищете, это в основном ссылка на прокси. Вы не хотите разыменования в PyObject*, вы хотите разыменования во что-то, что само по себе может дать вам PyObject*, Это похоже на то, как итераторы для таких типов, как vector<bool> вести себя.

В основном, вы хотите operator*() чтобы дать вам что-то вроде:

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

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector