Как выставить классы C++ с помощью const_iterator

Я использую Boost.Python для предоставления Сторонний API C++.

Файл заголовка, к которому я пришел, объявляет итерируемый класс (имеет методы begin и end) и пользовательский класс итератора, с помощью которого выполняется итерация: -

// File: data.hpp

#include <utility> // for std::pair
#include <cstring> // for size_t

namespace notmylib {

    // forward declaration
    class DataIterator;

    // Storage for arbitrary data
    class Data
    {
        public:
            Data(void);
            virtual ~Data(void);
            // ...
            typedef DataIterator const_iterator;
            const_iterator begin(void) const;
            const_iterator end(void) const;

            typedef std::pair<int, int> TRange;
        private:
            TRange m_data;
    };

    // Data iterator class
    class DataIterator
    {
        public:
            // constructors
            DataIterator(void);
            DataIterator(const Data);
            ~DataIterator(void);

            // copy constructor
            DataIterator(const DataIterator& iter);
            // assignment operator
            DataIterator& operator=(const DataIterator& iter);

            // Comparison operators
            bool operator==(const DataIterator& iter) const;
            bool operator!=(const DataIterator& iter) const;

            // Data Range
            typedef TData::TRange TRange;
            TRange  GetRange(void) const;
            Data    GetRangeAsData(void) const;

            // Go backwards one step
            void   Rewind(void);
        private:
            Data   m_data;
            size_t m_index;
    };
}

Я создал минимальные классы-оболочки, полученные из них: -

// File: pydata.hpp
#include "data.hpp"

namespace mylib {
    class PyData
        : public notmylib::Data
    {
        public:
            PyData(void);
            virtual ~PyData(void);
    };

    class PyIterator
        : public notmylib::DataIterator
    {
        public:
            PyIterator(void);
            PyIterator(const notmylib::Data);
            PyIterator(const PyIterator& iter);

            ~PyIterator(void);
    };
}

И объявление Boost.Python: -

// File: pydata.cpp
#include "pydata.hpp"

#include <boost/python/class.hpp>
#include <boost/python/iterator.hpp>
#include <boost/python/module.hpp>

BOOST_PYTHON_MODULE(const_iterator)
{
    using namespace boost::python;

    class_<mylib::PyData, boost::noncopyable>("Data",
            "Iterable Data storage class.")
        .def("__iter__",
            iterator<const mylib::PyData>() /*, // */ )      ///< iterator / range / iterators ?
         //   boost::python::return_value_policy<            ///< This CallPolicy 
         //       boost::python::copy_const_reference> >() ) ///  doesn't work either
        ;

    class_<mylib::PyIterator>("DataIterator",
            "Iterator for Data class. Don't actually need to expose...")
        .def("__eq__", &mylib::PyIterator::operator==)
        .def("__neq__", &mylib::PyIterator::operator!=)
        // ...
        ;
}

Единственная странность здесь, кажется, заключается в использовании определения типа const_iterator. Это описано в Boost.Python документацию по итератору, и, насколько я понимаю, все, что ему нужно, это квалификатор const в параметрах шаблона iterator. то есть

boost::python::iterator<const mylib::PyData>()

Однако это приводит к следующей ошибке компилятора при использовании GCC 4.7.2 в Linux x86_64:

g++ -std=gnu++98 -c -g -O1  -fPIC -I/usr/include/python2.7  pydata.cpp -o pydata.o
In file included from /usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_algobase.h:66:0,
                 from /usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/memory:64,
                 from /usr/include/boost/config/no_tr1/memory.hpp:21,
                 from /usr/include/boost/get_pointer.hpp:14,
                 from /usr/include/boost/python/object/pointer_holder.hpp:11,
                 from /usr/include/boost/python/to_python_indirect.hpp:10,
                 from /usr/include/boost/python/converter/arg_to_python.hpp:10,
                 from /usr/include/boost/python/call.hpp:15,
                 from /usr/include/boost/python/object_core.hpp:14,
                 from /usr/include/boost/python/object/class.hpp:9,
                 from /usr/include/boost/python/class.hpp:13,
                 from pydata.cpp:4:
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_iterator_base_types.h: In instantiation of 'struct std::iterator_traits<notmylib::DataIterator>':
/usr/include/boost/detail/iterator.hpp:81:8:   required from 'struct boost::detail::iterator_traits<notmylib::DataIterator>'
/usr/include/boost/python/object/iterator.hpp:58:17:   required from 'struct boost::python::objects::iterator_range<boost::python::return_value_policy<boost::python::return_by_value>, notmylib::DataIterator>::next'
/usr/include/boost/python/object/iterator.hpp:127:45:   required from 'boost::python::api::object boost::python::objects::detail::demand_iterator_class(const char*, Iterator*, const NextPolicies&) [with Iterator = notmylib::DataIterator; NextPolicies = boost::python::return_value_policy<boost::python::return_by_value>]'
/usr/include/boost/python/object/iterator.hpp:167:11:   required from 'boost::python::objects::iterator_range<NextPolicies, Iterator> boost::python::objects::detail::py_iter_<Target, Iterator, Accessor1, Accessor2, NextPolicies>::operator()(boost::python::back_reference<Target&>) const [with Target = const mylib::PyData; Iterator = notmylib::DataIterator; Accessor1 = boost::_bi::protected_bind_t<boost::_bi::bind_t<notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&), boost::_bi::list1<boost::arg<1> > > >; Accessor2 = boost::_bi::protected_bind_t<boost::_bi::bind_t<notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&), boost::_bi::list1<boost::arg<1> > > >; NextPolicies = boost::python::return_value_policy<boost::python::return_by_value>]'
/usr/include/boost/python/detail/invoke.hpp:75:82:   required from 'PyObject* boost::python::detail::invoke(boost::python::detail::invoke_tag_<false, false>, const RC&, F&, AC0&) [with RC = boost::python::to_python_value<const boost::python::objects::iterator_range<boost::python::return_value_policy<boost::python::return_by_value>, notmylib::DataIterator>&>; F = boost::python::objects::detail::py_iter_<const mylib::PyData, notmylib::DataIterator, boost::_bi::protected_bind_t<boost::_bi::bind_t<notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&), boost::_bi::list1<boost::arg<1> > > >, boost::_bi::protected_bind_t<boost::_bi::bind_t<notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&), boost::_bi::list1<boost::arg<1> > > >, boost::python::return_value_policy<boost::python::return_by_value> >; AC0 = boost::python::arg_from_python<boost::python::back_reference<const mylib::PyData&> >; PyObject = _object]'
/usr/include/boost/python/detail/caller.hpp:223:13:   required from 'PyObject* boost::python::detail::caller_arity<1u>::impl<F, Policies, Sig>::operator()(PyObject*, PyObject*) [with F = boost::python::objects::detail::py_iter_<const mylib::PyData, notmylib::DataIterator, boost::_bi::protected_bind_t<boost::_bi::bind_t<notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&), boost::_bi::list1<boost::arg<1> > > >, boost::_bi::protected_bind_t<boost::_bi::bind_t<notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&), boost::_bi::list1<boost::arg<1> > > >, boost::python::return_value_policy<boost::python::return_by_value> >; Policies = boost::python::default_call_policies; Sig = boost::mpl::vector2<boost::python::objects::iterator_range<boost::python::return_value_policy<boost::python::return_by_value>, notmylib::DataIterator>, boost::python::back_reference<const mylib::PyData&> >; PyObject = _object]'
/usr/include/boost/python/object/py_function.hpp:38:33:   required from 'PyObject* boost::python::objects::caller_py_function_impl<Caller>::operator()(PyObject*, PyObject*) [with Caller = boost::python::detail::caller<boost::python::objects::detail::py_iter_<const mylib::PyData, notmylib::DataIterator, boost::_bi::protected_bind_t<boost::_bi::bind_t<notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&), boost::_bi::list1<boost::arg<1> > > >, boost::_bi::protected_bind_t<boost::_bi::bind_t<notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&), boost::_bi::list1<boost::arg<1> > > >, boost::python::return_value_policy<boost::python::return_by_value> >, boost::python::default_call_policies, boost::mpl::vector2<boost::python::objects::iterator_range<boost::python::return_value_policy<boost::python::return_by_value>, notmylib::DataIterator>, boost::python::back_reference<const mylib::PyData&> > >; PyObject = _object]'
pydata.cpp:26:1:   required from here
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_iterator_base_types.h:166:53: error: no type named 'iterator_category' in 'class notmylib::DataIterator'
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_iterator_base_types.h:167:53: error: no type named 'value_type' in 'class notmylib::DataIterator'
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_iterator_base_types.h:168:53: error: no type named 'difference_type' in 'class notmylib::DataIterator'
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_iterator_base_types.h:169:53: error: no type named 'pointer' in 'class notmylib::DataIterator'
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/bits/stl_iterator_base_types.h:170:53: error: no type named 'reference' in 'class notmylib::DataIterator'

Как должен быть представлен такой итерируемый класс?

Привет, Алекс


person Alex Leach    schedule 27.03.2013    source источник
comment
Разве проблема не в том, что исходный итератор C++ не соответствует стандарту? Отсутствующие typedefs, кажется, намекают на это.   -  person bluescarni    schedule 27.03.2013
comment
Это, без сомнения, правда; Я понятия не имею, когда дело доходит до соответствия стандартам C++. Авторы библиотеки, кажется, заново изобрели колесо/стандартную библиотеку, но есть много совпадений... Я только что нашел iterator_traits, который, я думаю, можно использовать для добавления этих отсутствующих типов одним штрихом. Возможно, это могло бы стандартизируйте это для меня; Я всегда могу добавить материал в промежуточные Py(Data|Iterator) классы..   -  person Alex Leach    schedule 27.03.2013
comment
Я подозреваю, что Boost.Python полагается на то, что итератор будет соответствовать стандарту для работы. Вы можете попытаться обернуть итератор с помощью механизма iterator_facade от Boost: boost.org/doc/libs/1_53_0/libs/iterator/doc/ (это то, что я использую при написании собственных итераторов).   -  person bluescarni    schedule 27.03.2013
comment
Выглядит многообещающе, тем более что один из его авторов — тот же парень, что написал Boost.Python. Спасибо за предложение!   -  person Alex Leach    schedule 27.03.2013
comment
Да, iterator_facade сделал свое дело. Спасибо! Если вы хотите опубликовать это как ответ, я добавлю код, который сработал, и приму его;)   -  person Alex Leach    schedule 27.03.2013
comment
Я отправил код к вашему ответу, но похоже, что он не прошел экспертную оценку... Жду, появится ли он снова в улучшенной форме. Желаемое, однако :)   -  person Alex Leach    schedule 27.03.2013


Ответы (1)


Я подозреваю, что Boost.Python использует DataIterator как стандартный итератор C++ для работы.

Вы можете попробовать обернуть итератор, используя механизм iterator_facade от Boost:

http://www.boost.org/doc/libs/release/libs/iterator/doc/iterator_facade.html

person bluescarni    schedule 27.03.2013