1

I have the following C++ code:

    struct MyType { int x, y; };
    struct A { 
        std::vector<MyType> get_data();
    };

which I want to interface to Python using Boost Python so that it can be used in the following way:

    a = A()
    ret = a.get_data();
    for r in ret:
        print('x=%d; y=%d;' % (r['x'], r['y']))

What I have now is a rather naive:

    BOOST_PYTHON_MODULE(pyA) { 
        class_<A>("A").def("get_data", &A::get_data);
    }

which gives me, as expected, the following error

     TypeError: No to_python (by-value) converter found for C++ type

when I try to call the get_data() function from the Python code.

I have seen posts on here (such as std::vector to boost::python::list) which describe how to use vector_indexing_suite to convert a std::vector<T> to a list for some types T (e.g. floats, strings), but I'm not sure how to extend this to deal with my struct -> dict conversion as well. Any help would be greatly appreciated.

2 Answers 2

2

Below, how to expose your C++ code to Python. MyType needs 'equal to' comparison operator overloaded and also MyType itself needs to be exposed to Python.

#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
using namespace boost::python;

struct MyType { 
    int x, y;  
    bool operator==(const MyType& data) const {
        return this->x == data.x && this->y == data.y;
    }   
};
struct A { 
    std::vector<MyType> get_data() const { return {{1,2},{3,4}};};
};

BOOST_PYTHON_MODULE(pyA) {
    class_<MyType>("MyType")
        .def_readwrite("x", &MyType::x)
        .def_readwrite("y", &MyType::y);
    class_<std::vector<MyType>>("MyList")
        .def(vector_indexing_suite<std::vector<MyType>>());
    class_<A>("A").def("get_data", &A::get_data);
}

Below slightly modified Python script. get_data() return type is of a list so it needs to be accessed as such. If you want it to be a dict then convert it to dict in Python.

import pyA 

a = pyA.A()
ret = a.get_data();
for r in ret:
    print('x=%d; y=%d;' % (r.x, r.y))
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much for your reply. In the end I figured it out myself, and I chose my solution as it more directly implements what I wanted. But I'm really grateful that you took the time to help and reply to my post, it is much appreciated.
1

In the end I adopted a solution like the following, which I post here in case it is useful to somebody else in the future. This can be improved by adding boost's "readonly" qualifier, but I haven't done so yet.

#include <boost/python.hpp>
using namespace boost::python;

struct Point { 
    int x, y;
};

using Points = std::vector<Point>;

struct Converter
{
    static PyObject* convert(const Points& v)
    {
        boost::python::list ret;
        for (const auto& c : v) {
            boost::python::dict *r = new boost::python::dict();
            (*r)["x"] = c.x;
            (*r)["y"] = c.y;
            ret.append(boost::python::object(*r));
         }
        return boost::python::incref(ret.ptr());
    }
};

BOOST_PYTHON_MODULE(mymodule)
{
    boost::python::to_python_converter<Points, Converter>();

    class_<MyClass, boost::noncopyable>("MyClass")
        .def("get_data", &MyClass::get_data);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.