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 \
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; \
static_assert(Index < boost::mp11::mp_size<members>()); \
return arg.*boost::mp11::mp_at_c().pointer; \
} \
template \
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; \
static_assert(Index < boost::mp11::mp_size<members>()); \
return arg.*boost::mp11::mp_at_c().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
inline constexpr bool is_constant_initialized_front(const Type(&arg)[Size]) noexcept
{
static_assert(Size > 0);
return is_constant_initialized(arg[0]);
}
template
inline constexpr bool is_constant_initialized_front(const std::array& 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;
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::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(m128)); // works with gcc, clang, intel
Do you have an idea how to implement __builtin_constant_p for all compilers?
thx
Gero