Boost logo

Boost :

Subject: [boost] [python] non-standard iteration / wrapping member function return value
From: Matus Chochlik (chochlik_at_[hidden])
Date: 2013-06-04 13:07:47


Hi,

I'm stuck at trying to make python bindings for a set of classes that use a
non-c++-standard iteration protocol. I've made a minimal example of what
I'm trying to do:

the python-ized classes look in essence like this:

//-------------------------------------------------------------
class int_range
{
private:
        int i, max;
public:
        int_range(int m) : i(0), max(m) { }

        bool empty(void) const { return i > max; }
        int front(void) const { return i; }
        void next(void) { ++i; }
};

class range_maker
{
public:
        int_range make(void) const { return int_range(10); }
};
//-------------------------------------------------------------

the boost.python module that I've come up with so far:

//-------------------------------------------------------------
using namespace boost::python;

class _py_int_range_iter
{
private:
        int_range _range;
public:
        _py_int_range_iter(int_range range) : _range(range) { }

        _py_int_range_iter self(void) { return *this; }

        int next(void)
        {
                if(_range.empty())
                        objects::stop_iteration_error();
                int result = _range.front();
                _range.next();
                return result;
        }
};

class_<_py_int_range_iter>("_py_int_range_iter", init<const int_range&>())
        .def("self", &_py_int_range_iter::self)
        .def("next", &_py_int_range_iter::next)
;

class _py_int_range
{
private:
        int_range _range;
public:
        _py_int_range(int_range range) : _range(range) { }

        _py_int_range_iter iter(void)
        {
                return _py_int_range_iter(_range);
        }
};

class_<_py_int_range>("_py_int_range", init<const int_range&>())
        .def("__iter__", &_py_int_range::iter)
;
//-------------------------------------------------------------

the problem is that when I register range_maker as follows...

//-------------------------------------------------------------
class_<range_maker>("range_maker")
        .def("make", &range_maker::make)
;
//-------------------------------------------------------------

... it compiles but (obviously) fails in python at run-time because
range_maker::make returns int_range and not _py_int_range.

what do I need to do to make this work?

I know that I could write _py_range_maker wrapping range_maker and let it
return _py_int_range, but this approach does not scale very well.
Is there some way to tell the def(...) function that I want to wrap the
return value into an object of another type? Is there a return value policy
for that or do I need to write my own? If so how?

Thanks in advance

Matus


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk