[C++-sig] Iterators for heterogeneous container
Thomas Daniel
thomasd57 at yahoo.com
Sat Nov 7 23:25:41 CET 2009
troy d. straszheim wrote:
> Thomas Daniel wrote:
>>
>> BOOST_PYTHON_MODULE(vegetables)
>> {
>> class_<Garden>("Garden")
>> .def("get_potatoes", &Garden::get_potatoes)
>> .def("get_tomatoes", &Garden::get_tomatoes)
>> ;
>> class_<TomatoIter>("TomatoIter")
>> .def("__iter__", &TomatoIter::get_next)
>> ;
>> }
>>
>> That at least compiles - unlike all my previous attempts that
>> generate three pages of template errors - but python complain:
>>
>> TypeError: iter() returned non-iterator of type 'Tomato'
>>
>> so now I am trying to figure out how to tell boost that get_tomatoes
>> returns an iterator ...
>>
>
> Please don't top-post, guys
>
> As you know, python iterators have a function next() that returns the
> next object in the iteree, or throw StopIteration when they're at the
> end. As you also know, python expects member functions __iter__() to
> return an iterator. Is the thing returned by TomatoIter::get_next an
> iterator, ie does it implement the iterator interface?
>
> -t
>
>
Thank you very much for the email, you did put me on the right track and
I finally figured out how to do it, with help from here also:
http://wiki.python.org/moin/boost.python/iterator
The solution involves creating a wrapper class around get_next(), which
throws StopIteration when done and a "pass_through" function to bind to
__iter__:
inline TomatoIter pass_through(const TomatoIter& iter) { return iter; }
Tomato next(TomatoIter& iter) {
Tomato tomato = iter.get_next();
if (!tomato) {
PyErr_SetString(PyExc_StopIteration, "No more data.");
throw_error_already_set();
}
return tomato;
}
Now, I can do this:
BOOST_PYTHON_MODULE(Garden)
{
......
class_<TomatoIter>("TomatoIter", no_init)
.def("next", next)
.def("__iter__", pass_through)
;
and it works.
Thomas
More information about the Cplusplus-sig
mailing list