John Glen
John Glen

Reputation: 941

Problem with passing STL containers using pybind11

My goal is to be able to pass a std::map<double, double> from Python to C++, populate it in C++ and then see the results on the Python side. How is this achieved? I can't even get a std::vector to work.

I have a function definition in C++ like this

void predict(std::vector<T>& seq, std::map<T, double>& probabilities)

main.cpp looks like this

#include "node.h"
#include "probtree.h"
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>

PYBIND11_MAKE_OPAQUE(std::vector<double>);
PYBIND11_MAKE_OPAQUE(std::map<double, double>);

namespace py = pybind11;

using namespace std;

int main(int argc, char** argv){

}

PYBIND11_MODULE(sps_c, m){
    py::bind_vector<std::vector<double>>(m, "VectorD");
    py::bind_map<std::map<double, double>>(m, "MapDD");
    py::class_<ProbTree<double>>(m, "ProbTree")
        .def(py::init())
        .def("process", &ProbTree<double>::process)
        .def("predict", &ProbTree<double>::predict)
        ;
}

Nothing I expect to work works:

>>> import sps_c
>>> pt = sps_c.ProbTree
>>> vd = sps_c.VectorD
>>> m = sps_c.MapDD
>>> pt.process(vd)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: process(): incompatible function arguments. The following argument types are supported:
    1. (self: sps_c.ProbTree, arg0: sps_c.VectorD) -> None

Invoked with: <class 'sps_c.VectorD'>

Maybe a List?

>>> pt.process([1.0])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: process(): incompatible function arguments. The following argument types are supported:
    1. (self: sps_c.ProbTree, arg0: sps_c.VectorD) -> None

Invoked with: [1.0]

How do I make that work?

There is also an issue with STL methods not being available:

vd.push_back(1.0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'sps_c.VectorD' has no attribute 'push_back'

Do I have to write a bunch of boilerplate to get STL containers to work?

Upvotes: 1

Views: 1050

Answers (1)

unddoch
unddoch

Reputation: 6004

Your first example doesn't work because you're calling a method with a class and not with an instance. This should work, I think:

>>> pt = sps_c.ProbTree()
>>> vd = sps_c.VectorD()
>>> pt.process(vd)

Regarding your second example: There's no automatic type conversion, so you'll need to convert yourself:

>>> pt_instance.process(sps_c.VectorD(vd))

About the third example: push_back and other methods are available under their common Python names. This is not well documented, so here's a list of them (from here):

bind_vector exposes append, clear, extend, insert, pop, and some iterator methods. bind_map exposes keys, values, items, and some iterator methods.

Those methods might not be available if the contained types are not copyable.

Upvotes: 2

Related Questions