Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to expose C++ classes with const_iterator
    text
    copied!<p>I am using <a href="http://www.boost.org/doc/libs/1_53_0/libs/python/doc/index.html" rel="nofollow">Boost.Python</a> to expose a 3rd party C++ API.</p> <p>A header file I've come to declares an iterable class (has <code>begin</code> and <code>end</code> methods), and a custom iterator class with which to do the iteration:-</p> <pre><code>// File: data.hpp #include &lt;utility&gt; // for std::pair #include &lt;cstring&gt; // 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&lt;int, int&gt; TRange; private: TRange m_data; }; // Data iterator class class DataIterator { public: // constructors DataIterator(void); DataIterator(const Data); ~DataIterator(void); // copy constructor DataIterator(const DataIterator&amp; iter); // assignment operator DataIterator&amp; operator=(const DataIterator&amp; iter); // Comparison operators bool operator==(const DataIterator&amp; iter) const; bool operator!=(const DataIterator&amp; 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; }; } </code></pre> <p>I've created minimal wrapper classes deriving from these:-</p> <pre><code>// 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&amp; iter); ~PyIterator(void); }; } </code></pre> <p>And the Boost.Python declaration:-</p> <pre><code>// File: pydata.cpp #include "pydata.hpp" #include &lt;boost/python/class.hpp&gt; #include &lt;boost/python/iterator.hpp&gt; #include &lt;boost/python/module.hpp&gt; BOOST_PYTHON_MODULE(const_iterator) { using namespace boost::python; class_&lt;mylib::PyData, boost::noncopyable&gt;("Data", "Iterable Data storage class.") .def("__iter__", iterator&lt;const mylib::PyData&gt;() /*, // */ ) ///&lt; iterator / range / iterators ? // boost::python::return_value_policy&lt; ///&lt; This CallPolicy // boost::python::copy_const_reference&gt; &gt;() ) /// doesn't work either ; class_&lt;mylib::PyIterator&gt;("DataIterator", "Iterator for Data class. Don't actually need to expose...") .def("__eq__", &amp;mylib::PyIterator::operator==) .def("__neq__", &amp;mylib::PyIterator::operator!=) // ... ; } </code></pre> <p>The only oddity here seems to be the use of the <code>const_iterator</code> typedef. This is described in the Boost.Python <a href="http://www.boost.org/doc/libs/1_53_0/libs/python/doc/v2/iterator.html#iterator-spec" rel="nofollow">iterator documentation</a>, and from what I gather, all that it needs is a <code>const</code> qualifier in <code>iterator</code>'s template parameters. i.e.</p> <pre><code>boost::python::iterator&lt;const mylib::PyData&gt;() </code></pre> <p>However, that leads to the following compiler error, using GCC 4.7.2 on Linux x86_64:-</p> <pre><code>g++ -std=gnu++98 -c -g -O1 -fPIC -I/usr/include/python2.7 pydata.cpp -o pydata.o </code></pre> <pre><code>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&lt;notmylib::DataIterator&gt;': /usr/include/boost/detail/iterator.hpp:81:8: required from 'struct boost::detail::iterator_traits&lt;notmylib::DataIterator&gt;' /usr/include/boost/python/object/iterator.hpp:58:17: required from 'struct boost::python::objects::iterator_range&lt;boost::python::return_value_policy&lt;boost::python::return_by_value&gt;, notmylib::DataIterator&gt;::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&amp;) [with Iterator = notmylib::DataIterator; NextPolicies = boost::python::return_value_policy&lt;boost::python::return_by_value&gt;]' /usr/include/boost/python/object/iterator.hpp:167:11: required from 'boost::python::objects::iterator_range&lt;NextPolicies, Iterator&gt; boost::python::objects::detail::py_iter_&lt;Target, Iterator, Accessor1, Accessor2, NextPolicies&gt;::operator()(boost::python::back_reference&lt;Target&amp;&gt;) const [with Target = const mylib::PyData; Iterator = notmylib::DataIterator; Accessor1 = boost::_bi::protected_bind_t&lt;boost::_bi::bind_t&lt;notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&amp;), boost::_bi::list1&lt;boost::arg&lt;1&gt; &gt; &gt; &gt;; Accessor2 = boost::_bi::protected_bind_t&lt;boost::_bi::bind_t&lt;notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&amp;), boost::_bi::list1&lt;boost::arg&lt;1&gt; &gt; &gt; &gt;; NextPolicies = boost::python::return_value_policy&lt;boost::python::return_by_value&gt;]' /usr/include/boost/python/detail/invoke.hpp:75:82: required from 'PyObject* boost::python::detail::invoke(boost::python::detail::invoke_tag_&lt;false, false&gt;, const RC&amp;, F&amp;, AC0&amp;) [with RC = boost::python::to_python_value&lt;const boost::python::objects::iterator_range&lt;boost::python::return_value_policy&lt;boost::python::return_by_value&gt;, notmylib::DataIterator&gt;&amp;&gt;; F = boost::python::objects::detail::py_iter_&lt;const mylib::PyData, notmylib::DataIterator, boost::_bi::protected_bind_t&lt;boost::_bi::bind_t&lt;notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&amp;), boost::_bi::list1&lt;boost::arg&lt;1&gt; &gt; &gt; &gt;, boost::_bi::protected_bind_t&lt;boost::_bi::bind_t&lt;notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&amp;), boost::_bi::list1&lt;boost::arg&lt;1&gt; &gt; &gt; &gt;, boost::python::return_value_policy&lt;boost::python::return_by_value&gt; &gt;; AC0 = boost::python::arg_from_python&lt;boost::python::back_reference&lt;const mylib::PyData&amp;&gt; &gt;; PyObject = _object]' /usr/include/boost/python/detail/caller.hpp:223:13: required from 'PyObject* boost::python::detail::caller_arity&lt;1u&gt;::impl&lt;F, Policies, Sig&gt;::operator()(PyObject*, PyObject*) [with F = boost::python::objects::detail::py_iter_&lt;const mylib::PyData, notmylib::DataIterator, boost::_bi::protected_bind_t&lt;boost::_bi::bind_t&lt;notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&amp;), boost::_bi::list1&lt;boost::arg&lt;1&gt; &gt; &gt; &gt;, boost::_bi::protected_bind_t&lt;boost::_bi::bind_t&lt;notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&amp;), boost::_bi::list1&lt;boost::arg&lt;1&gt; &gt; &gt; &gt;, boost::python::return_value_policy&lt;boost::python::return_by_value&gt; &gt;; Policies = boost::python::default_call_policies; Sig = boost::mpl::vector2&lt;boost::python::objects::iterator_range&lt;boost::python::return_value_policy&lt;boost::python::return_by_value&gt;, notmylib::DataIterator&gt;, boost::python::back_reference&lt;const mylib::PyData&amp;&gt; &gt;; PyObject = _object]' /usr/include/boost/python/object/py_function.hpp:38:33: required from 'PyObject* boost::python::objects::caller_py_function_impl&lt;Caller&gt;::operator()(PyObject*, PyObject*) [with Caller = boost::python::detail::caller&lt;boost::python::objects::detail::py_iter_&lt;const mylib::PyData, notmylib::DataIterator, boost::_bi::protected_bind_t&lt;boost::_bi::bind_t&lt;notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&amp;), boost::_bi::list1&lt;boost::arg&lt;1&gt; &gt; &gt; &gt;, boost::_bi::protected_bind_t&lt;boost::_bi::bind_t&lt;notmylib::DataIterator, notmylib::DataIterator (*)(const mylib::PyData&amp;), boost::_bi::list1&lt;boost::arg&lt;1&gt; &gt; &gt; &gt;, boost::python::return_value_policy&lt;boost::python::return_by_value&gt; &gt;, boost::python::default_call_policies, boost::mpl::vector2&lt;boost::python::objects::iterator_range&lt;boost::python::return_value_policy&lt;boost::python::return_by_value&gt;, notmylib::DataIterator&gt;, boost::python::back_reference&lt;const mylib::PyData&amp;&gt; &gt; &gt;; 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' </code></pre> <p>How should such an iterable class be exposed?</p> <p>Cheers, Alex</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload