diff --git a/include/eigenpy/variant.hpp b/include/eigenpy/variant.hpp index 7c3fc50bafa4cbf76e78be6efd0e64015e7cc943..50772e06db0365fa1963e332c7fa94df82fe1764 100644 --- a/include/eigenpy/variant.hpp +++ b/include/eigenpy/variant.hpp @@ -12,6 +12,8 @@ #include <boost/mpl/for_each.hpp> #include <boost/mpl/vector.hpp> +#include <type_traits> + #ifdef EIGENPY_WITH_CXX17_SUPPORT #include <variant> #endif @@ -96,6 +98,7 @@ struct VariantValueToObject : VariantVisitorType<PyObject*, Variant> { using Base::operator(); }; + /// Convert {boost,std}::variant<class...> alternative reference to a Python /// object. This converter return the alternative reference. The code that /// create the reference holder is taken from \see @@ -110,7 +113,20 @@ struct VariantRefToObject : VariantVisitorType<PyObject*, Variant> { return Base::visit(VariantRefToObject(), v); } - template <typename T> + template <typename T, + typename std::enable_if< + std::is_arithmetic<typename std::remove_cv< + typename std::remove_reference<T>::type>::type>::value, + bool>::type = true> + result_type operator()(T t) const { + return boost::python::incref(boost::python::object(t).ptr()); + } + + template <typename T, + typename std::enable_if< + !std::is_arithmetic<typename std::remove_cv< + typename std::remove_reference<T>::type>::type>::value, + bool>::type = true> result_type operator()(T& t) const { return boost::python::detail::make_reference_holder::execute(&t); } @@ -198,6 +214,7 @@ struct VariantConverter { static void registration() { typedef details::VariantValueToObject<variant_type> variant_to_value; typedef typename details::VariantAlternatives<variant_type>::types types; + boost::python::to_python_converter<variant_type, variant_to_value>(); boost::mpl::for_each<types>( details::VariantImplicitlyConvertible<variant_type>()); diff --git a/unittest/python/test_variant.py.in b/unittest/python/test_variant.py.in index 761188f7c0978f86df1f478a5f84f1e4a6ac3d7d..e3b1eba0070b0a816636d8edb10b764d1ecac0ef 100644 --- a/unittest/python/test_variant.py.in +++ b/unittest/python/test_variant.py.in @@ -5,8 +5,10 @@ V1 = variant_module.V1 V2 = variant_module.V2 VariantHolder = variant_module.VariantHolder VariantNoneHolder = variant_module.VariantNoneHolder +VariantArithmeticHolder = variant_module.VariantArithmeticHolder make_variant = variant_module.make_variant make_variant_none = variant_module.make_variant_none +make_variant_arithmetic = variant_module.make_variant_arithmetic variant = make_variant() assert isinstance(variant, V1) @@ -46,10 +48,6 @@ assert variant_holder.variant.v == v2.v # Test variant that hold a None value v_none = make_variant_none() assert v_none is None -v_none = 1 -assert v_none == 1 -v_none = None -assert v_none is None variant_none_holder = VariantNoneHolder() v_none = variant_none_holder.variant @@ -62,3 +60,19 @@ assert variant_none_holder.variant.v == 1 v1 = variant_none_holder.variant v1.v = 10 assert variant_none_holder.variant.v == 10 +# variant_none_holder.variant = None + + +# Test variant that hold base type +v_arithmetic = make_variant_arithmetic() +assert isinstance(v_arithmetic, int) + +variant_arithemtic_holder = VariantArithmeticHolder() +assert isinstance(variant_arithemtic_holder.variant, int) +variant_arithemtic_holder.variant = 2.0 +assert variant_arithemtic_holder.variant == 2 +assert isinstance(variant_arithemtic_holder.variant, float) +# Arithmetic type doesn't support reference +v1 = variant_arithemtic_holder.variant +v1 = 3 +assert variant_arithemtic_holder.variant != v1 diff --git a/unittest/variant.cpp.in b/unittest/variant.cpp.in index 3c0853617e1b02b62e541cce891297082bc2009f..3a99cae3fbba2ad6b7b8c76de1f24622a17c05b6 100644 --- a/unittest/variant.cpp.in +++ b/unittest/variant.cpp.in @@ -34,10 +34,14 @@ struct MyVariantNoneHelper<std::variant<Alternatives...> > { typedef typename MyVariantNoneHelper<VARIANT<V1> >::type MyVariantNone; +typedef VARIANT<int, double> MyVariantArithmetic; + MyVariant make_variant() { return V1(); } MyVariantNone make_variant_none() { return MyVariantNone(); } +MyVariantArithmetic make_variant_arithmetic() { return MyVariantArithmetic(); } + struct VariantHolder { MyVariant variant; }; @@ -46,6 +50,10 @@ struct VariantNoneHolder { MyVariantNone variant; }; +struct VariantArithmeticHolder { + MyVariantArithmetic variant; +}; + BOOST_PYTHON_MODULE(@MODNAME@) { using namespace eigenpy; @@ -74,4 +82,16 @@ BOOST_PYTHON_MODULE(@MODNAME@) { bp::make_getter(&VariantNoneHolder::variant, ConverterNone::return_internal_reference()), bp::make_setter(&VariantNoneHolder::variant)); + + typedef eigenpy::VariantConverter<MyVariantArithmetic> ConverterArithmetic; + ConverterArithmetic::registration(); + bp::def("make_variant_arithmetic", make_variant_arithmetic); + + boost::python::class_<VariantArithmeticHolder>("VariantArithmeticHolder", + bp::init<>()) + .add_property( + "variant", + bp::make_getter(&VariantArithmeticHolder::variant, + ConverterArithmetic::return_internal_reference()), + bp::make_setter(&VariantArithmeticHolder::variant)); }