Hi. While I haven't really found a way to get reference semantics (hints appreciated), I have now made my discoveries from https://blind.guru/boost_python-and-boost_variant.html into a handy little utility class. This is the best I was able to figure out regarding integration of boost::python with boost::variant. I was hoping to be able to utilize some sort of custom instance_holder, but it seems the library forces me to declare the C++ type for the object held. This prevents me from using a visitor to create the python object at runtime. I would basically need something that returns a boost::python::object, not a concrete C++ type. I haven't found that in the docs/code so far. The best I could find was to_python_converter, but that (at least to me) seems limited to copy semantics.
Any hint on how to improve the helper below is very welcome. Maybe someone finds it useful. There seems to be virtually nothing on the Net about this topic. ---<variant_adaptor.hpp>--- #if !defined(MLANG_PYTHON_VARIANT_ADAPTOR_HPP) #define MLANG_PYTHON_VARIANT_ADAPTOR_HPP #include <boost/python/implicit.hpp> #include <boost/python/object.hpp> #include <boost/python/to_python_converter.hpp> #include <boost/variant.hpp> namespace mlang { namespace python { template<typename Variant> struct variant_adaptor { variant_adaptor() { boost::python::to_python_converter<Variant, variant_adaptor>{}; register_convertibles<Variant>::apply(); } template<typename T> struct register_convertibles; template<typename T> struct register_convertibles<boost::variant<T>> { static void apply() { boost::python::implicitly_convertible<T, Variant>(); } }; template<typename T, typename... Ts> struct register_convertibles<boost::variant<T, Ts...>> { static void apply() { boost::python::implicitly_convertible<T, Variant>(); register_convertibles<boost::variant<Ts...>>::apply(); } }; static PyObject *convert(Variant const &v) { return apply_visitor(to_python{}, v); } struct to_python : boost::static_visitor<PyObject *> { template<typename T> result_type operator()(T const &t) const { return boost::python::incref(boost::python::object(t).ptr()); } }; }; } // namespace python } // namespace mlang #endif // !defined(MLANG_PYTHON_VARIANT_ADAPTOR_HPP) ---<snip>--- A small usage example would be: #include <boost/python/class.hpp> #include <boost/python/def.hpp> #include <boost/python/init.hpp> #include <boost/python/module.hpp> #include <boost/python/object.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp> #include "variant_adaptor.hpp" #include <vector> struct a { int x; }; struct b { std::string y; }; bool operator==(a const &lhs, a const &rhs) { return lhs.x == rhs.x; } bool operator==(b const &lhs, b const &rhs) { return lhs.y == rhs.y; } typedef boost::variant<a, b> variant; typedef std::vector<variant> vector; variant make_variant() { return variant(); } vector make_vector() { return vector{a(), b(), a()}; } BOOST_PYTHON_MODULE(bpva) { using namespace boost::python; // Define classes for all variant member types class_<a>("a", init<a>()).def(init<>()).def_readwrite("x", &a::x); class_<b>("b", init<b>()).def(init<>()).def_readwrite("y", &b::y); mlang::python::variant_adaptor<variant>{}; class_<vector>("vector").def(vector_indexing_suite<vector, true>()); def("make_variant", make_variant); def("make_vector", make_vector); } As described in the blog post above, the resulting Python module does work, but it does not allow to assign to members of a container element. Replacing a container element with a new one does work though. So while the Python behaviour is a bit unexpected, it is likely OKish for most use cases. I wonder if I am * missing an obvious technique to get this right, OR * hitting a fundamental limitation of Boost.Python, OR * hitting a fundamental limitation of value semantics vs. dynamic languages? -- CYa, ⡍⠁⠗⠊⠕ _______________________________________________ Cplusplus-sig mailing list Cplusplus-sig@python.org https://mail.python.org/mailman/listinfo/cplusplus-sig