title: How to expose C++ classes with const_iterator
body: <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>