C++/Python: Boost.Python でカスタムコンバーターを作る
C++ のクラスを Python で扱うとき、std::pair などのクラスはデフォルトでは型変換が行われない。自分でコンバーターを書く必要がある。
以下はコードの例。C++11のラムダ式を利用したら綺麗にまとまった。
#include <boost/python.hpp> #include "your_code.hpp" namespace yourmodulename { namespace py = boost::python; /* * Converter for result set (std::vector of std::pair => pylist of pytuple) */ namespace detail { template <typename T, typename U> struct pair_vector_to_tuple_list { static PyObject* convert(std::vector<std::pair<T, U> > const& ps) { py::list ret; for (auto it: ps) ret.append(py::make_tuple(it.first, it.second)); return py::incref(ret.ptr()); } static PyTypeObject const* get_pytype() { return &PyList_Type; } }; } template <typename T, typename U> void expose_pair_vector_to_tuple_list() { py::to_python_converter<std::vector<std::pair<T, U> >, detail::pair_vector_to_tuple_list<T, U>, true>(); } /* * Converter for list parameter (pylist => std::vector) */ template <typename T> void expose_pylist_to_vector() { typedef std::vector<T> VT; auto convertible = [](PyObject* obj_ptr) -> void* { return PySequence_Check(obj_ptr) ? obj_ptr : NULL; }; auto construct = [](PyObject* obj_ptr, py::converter::rvalue_from_python_stage1_data* data) { VT* storage = new (reinterpret_cast<py::converter::rvalue_from_python_storage<VT>*>(data)->storage.bytes) VT(); for (py::ssize_t i = 0, l = PySequence_Size(obj_ptr); i < l; ++i) { storage->push_back(py::extract<typename boost::range_value<VT>::type>(PySequence_GetItem(obj_ptr, i))); } data->convertible = storage; }; py::converter::registry::push_back(convertible, construct, py::type_id<VT>()); } } BOOST_PYTHON_MODULE(yourmodulename) { using namespace boost::python; using namespace yourmodulename; // expose converters expose_pair_vector_to_tuple_list<int, double>(); expose_pylist_to_vector<int>(); // expose classes ... }
なかなかに魔力を吸い取られそうなコードだ。
Related Posts
- mog project: C++/Python: Diving Into Boost.Python
- mog project: C++/Python: How to run Boost.Python module using setup.py with Python3.4 on Mac
0 件のコメント:
コメントを投稿