Hello, first of all, thank you very much for the great work. But I miss the support for unions. Is that correct? namespace boost { namespace describe { #define BOOST_DESCRIBE_UNION(C, Public) \ static_assert(std::is_union<C>::value, "BOOST_DESCRIBE_UNION should only be used with union types"); \ BOOST_DESCRIBE_PUBLIC_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Public) \ BOOST_DESCRIBE_PROTECTED_MEMBERS_(C) \ BOOST_DESCRIBE_PRIVATE_MEMBERS_(C) } // describe } // boost This version only supports public members. I also miss the support for std::get. Is that correct? namespace boost { namespace describe { #define BOOST_DESCRIBE_GET(C) \ template <std::size_t Index> \ inline constexpr const auto& get(const C& arg) noexcept \ { \ static_assert(std::is_class<C>::value || std::is_union<C>::value, "BOOST_DESCRIBE_GET should only be used with class, struct or union types"); \ using members = boost::describe::describe_members<C, boost::describe::mod_any_access>; \ static_assert(Index < boost::mp11::mp_size<members>()); \ return arg.*boost::mp11::mp_at_c<members, Index>().pointer; \ } \ template <std::size_t Index> \ inline constexpr auto& get(C& arg) noexcept \ { \ static_assert(std::is_class<C>::value || std::is_union<C>::value, "BOOST_DESCRIBE_GET should only be used with class, struct or union types"); \ using members = boost::describe::describe_members<C, boost::describe::mod_any_access>; \ static_assert(Index < boost::mp11::mp_size<members>()); \ return arg.*boost::mp11::mp_at_c<members, Index>().pointer; \ } } // describe } // boost However, the access rights are not taken into account. E.g.: struct A { int i; float f; }; BOOST_DESCRIBE_STRUCT(A, (), (i, f)) namespace std { BOOST_DESCRIBE_GET(A) } // std This also solves a very special problem, provided the compiler supports it: active member of a constexp union. Problem: union U { int64_t i; double d; }; constexpr U u{.d{3.1415}}; constexpr auto i=u.i; -> error In short: namespace std { template <typename Type> inline constexpr bool is_constant_initialized(const Type& arg) noexcept { #if __has_builtin(__builtin_constant_p) return __builtin_constant_p(arg); #elif defined(BOOST_MSVC) ??? #else static_assert(false, "is_constant_initialized not supportet"); return false; #endif } template <typename Type> inline constexpr bool is_constant_initialized_front(const Type& arg) noexcept { return is_constant_initialized(arg); } template <typename Type, size_t Size> inline constexpr bool is_constant_initialized_front(const Type(&arg)[Size]) noexcept { static_assert(Size > 0); return is_constant_initialized(arg[0]); } template <typename Type, size_t Size> inline constexpr bool is_constant_initialized_front(const std::array<Type, Size>& arg) noexcept { static_assert(Size > 0); return is_constant_initialized(arg[0]); } } // std namespace boost { namespace describe { template <typename Type> inline constexpr std::size_t active_index(const Type& arg) noexcept { static_assert(std::is_union_v<Type>); using any = describe_members<Type, mod_any_access>; std::size_t result{0}, index{0}; bool first{true}; boost::mp11::mp_for_each<any>([&](const auto& desc) constexpr noexcept { const auto& elem{arg.*desc.pointer}; if (std::is_constant_initialized_front(elem)) { if (first) { first = false; result = index; } } ++index; }); return first ? 0 : result; } template <auto Value> inline constexpr std::size_t active_index_v = std::integral_constant<std::size_t, active_index(Value)>::value; } // describe } // boost union __mm128_emu { float m128_f32[4]; double m128_f64[2]; int64_t m128_i64[2]; int32_t m128_i32[4]; int16_t m128_i16[8]; int8_t m128_i8[16]; uint64_t m128_u64[2]; uint32_t m128_u32[4]; uint16_t m128_u16[8]; uint8_t m128_u8[16]; }; BOOST_DESCRIBE_UNION(__mm128_emu, (m128_f32, m128_f64, m128_i64, m128_i32, m128_i16, m128_i8, m128_u64, m128_u32, m128_u16, m128_u8)) namespace std { BOOST_DESCRIBE_GET(__mm128_emu) } // std constexpr __mm128_emu m128{.m128_u32{4711}}; constexpr auto arr = std::to_array(std::get<boost::describe::active_index_v<m128>>(m128)); // works with gcc, clang, intel Do you have an idea how to implement __builtin_constant_p for all compilers? thx Gero
Gero Peterhoff wrote:
Hello, first of all, thank you very much for the great work. But I miss the support for unions. Is that correct? namespace boost { namespace describe { #define BOOST_DESCRIBE_UNION(C, Public) \ static_assert(std::is_union<C>::value, "BOOST_DESCRIBE_UNION should only be used with union types"); \ BOOST_DESCRIBE_PUBLIC_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Public) \ BOOST_DESCRIBE_PROTECTED_MEMBERS_(C) \ BOOST_DESCRIBE_PRIVATE_MEMBERS_(C) } // describe } // boost
Interesting point. In principle, BOOST_DESCRIBE_STRUCT and BOOST_DESCRIBE_CLASS should support unions, and a separate macro shouldn't be needed. So the static_assert on is_class is probably too strict and needs to be relaxed. However, I suspect that most code supporting described classes won't work correctly when passed a union. The examples in the documentation don't, so they would need to be updated with a check for is_class.
I also miss the support for std::get. Is that correct? namespace boost { namespace describe { #define BOOST_DESCRIBE_GET(C) \ template <std::size_t Index> \ inline constexpr const auto& get(const C& arg) noexcept \ { \ static_assert(std::is_class<C>::value || std::is_union<C>::value, "BOOST_DESCRIBE_GET should only be used with class, struct or union types"); \ using members = boost::describe::describe_members<C, boost::describe::mod_any_access>; \ static_assert(Index < boost::mp11::mp_size<members>()); \ return arg.*boost::mp11::mp_at_c<members, Index>().pointer; \ } \ template <std::size_t Index> \ inline constexpr auto& get(C& arg) noexcept \ { \ static_assert(std::is_class<C>::value || std::is_union<C>::value, "BOOST_DESCRIBE_GET should only be used with class, struct or union types"); \ using members = boost::describe::describe_members<C, boost::describe::mod_any_access>; \ static_assert(Index < boost::mp11::mp_size<members>()); \ return arg.*boost::mp11::mp_at_c<members, Index>().pointer; \ } } // describe } // boost
It's not clear why this needs to be std::get; adding overloads to namespace std is undefined behavior. It might be better off as a helper function in some namespace of your own. And a helper function of your own wouldn't need to be defined via a macro, it can be templated on C. template<std::size_t Index, class C> inline constexpr auto& get(C& arg) noexcept { using members = boost::describe::describe_members<C, boost::describe::mod_any_access>; static_assert(Index < boost::mp11::mp_size<members>()); return arg.*boost::mp11::mp_at_c<members, Index>().pointer; }
Do you have an idea how to implement __builtin_constant_p for all compilers?
I can't think of a way.
Interesting point. In principle, BOOST_DESCRIBE_STRUCT and BOOST_DESCRIBE_CLASS should support unions, and a separate macro shouldn't be needed. So the static_assert on is_class is probably too strict and needs to be relaxed.
However, I suspect that most code supporting described classes won't work correctly when passed a union. The examples in the documentation don't, so they would need to be updated with a check for is_class.
Just. Currently it is probably better to make a strict distinction.
It's not clear why this needs to be std::get; adding overloads to namespace std is undefined behavior. It might be better off as a helper function in some namespace of your own.
And a helper function of your own wouldn't need to be defined via a macro, it can be templated on C.
template<std::size_t Index, class C> inline constexpr auto& get(C& arg) noexcept { using members = boost::describe::describe_members<C, boost::describe::mod_any_access>; static_assert(Index < boost::mp11::mp_size<members>()); return arg.*boost::mp11::mp_at_c<members, Index>().pointer; }
You don't have to instantiate get in std. That's why I did it as a macro.
Do you have an idea how to implement __builtin_constant_p for all compilers?
I can't think of a way.
I have found https://github.com/nemequ/attic/blob/master/is_constant.h . But doesn't work :-( But that should be with the upcoming reflections https://en.cppreference.com/w/cpp/experimental/reflect https://en.cppreference.com/w/cpp/experimental/reflect/Constant to be possible? regards Gero
participants (2)
-
Gero Peterhoff
-
Peter Dimov