Search code examples
pythonc++c++11boost-python

Exposing std::vector<struct> with boost.python


I have an existing c++ code library that uses a struct with std::vector, which should be exposed to python.

in the header:

struct sFOO
{
    unsigned int start = 3 ;
    double foo = 20.0 ;
};

in the cpp:

namespace myName
{
myfoo::myfoo(){   
    sFOO singlefoo;
    std::vector<sFOO> foos;
}
sFOO singlefoo;            

std::vector<sFOO>* myfoo::get_vector(){
    return &foos;
}
}

and for boost::python snippet:

using namespace boost::python;

class dummy3{};

BOOST_PYTHON_MODULE(vStr)
{
scope myName = class_<dummy3>("myName");

class_<myName::sFOO>("sFOO")
    .add_property("start",&myName::sFOO::start)
    .add_property("foo",&myName::sFOO::foo)
    ;

class_<myName::myfoo>("myfoo", no_init)
    .def(init<>())
    .def("checkfoo",&myName::myfoo::checkfoo)
    .add_property("foos",&myName::myfoo::foos) 
    .add_property("singlefoo",&myName::myfoo::singlefoo)
}

(FYI, fictitious class dummy3 is used to simulate namespace, and using scope is therefore not an option.)

A compilation and importing processes are OK, and I can access singlefoo, but whenever I try to access vector foos, I encounter the error message below.

Python class registered for C++ class std::vector<myName::sFOO, 
std::allocator<myName::sFOO> >

To circumvent this issue, I've firstly tried vector_indexing_suite, but it didn't help exposing pre-defined vector of struct.

I also assumed that there should be a solution related to exposing pointer to python, so I have tried to get a pointer by following:

    .def("get_vector",&myName::myfoo::get_vector) 

which produces compile Error.

Since I am quite a novice to both C++ and Boost, any comments including solution, tips for search, and a suggestion to suitable reference would be greatly appreciated.

Thanks in advance!


Solution

  • Method .def("get_vector",&myName::myfoo::get_vector) is not working because it returns a pointer to a vector, so it's necessary to inform the policy that defines how object ownership should be managed:

    class_<myName::myfoo>("myfoo", no_init)
       // current code
       .def("get_vector", &myfoo::get_vector, return_value_policy<reference_existing_object>())
    ;
    

    In order to use vector_indexing_suite, it is necessary to implement the equal to operator to the class that it holds:

    struct sFOO
    {
        unsigned int start = 3 ;
        double foo = 20.0 ;
    
        bool operator==(const sFOO& rhs)
        {
            return this == &rhs; //< implement your own rules.
        }
    };
    

    then you can export the vector:

    #include <boost/python/suite/indexing/vector_indexing_suite.hpp>
    
    class_<std::vector<sFOO>>("vector_sFOO_")
       .def(vector_indexing_suite<std::vector<sFOO>>())
    ;