mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-19 04:22:13 +00:00
Document the unions behavior and fix #22
This commit is contained in:
35
doc/pfr.qbk
35
doc/pfr.qbk
@@ -184,6 +184,41 @@ Argument Dependant Lookup works well, `std::less` will find the operators for `s
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section Reflection of unions ]
|
||||
|
||||
With [*precise] reflection you could do reflection if a type contains union. But be sure that operations for union are manually defined:
|
||||
|
||||
```
|
||||
#include <boost/pfr/precise/ops.hpp>
|
||||
|
||||
union test_union {
|
||||
int i;
|
||||
float f;
|
||||
};
|
||||
|
||||
inline bool operator==(test_union l, test_union r) noexcept; // Compile time error without this operator
|
||||
|
||||
|
||||
struct foo { int i; test_union u; };
|
||||
|
||||
bool some_function(foo f1, foo f2) {
|
||||
using namespace boost::pfr::ops;
|
||||
return f1 == f2; // OK
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
[*Flat] reflection of types that contain unions is disabled.
|
||||
[*Flat] and [*precise] reflection of unions is disabled for safety reasons. There's a way to reflect the first member of a union and use it. Unfortunately there's no way to find out [*active] member of a union. Accessing an inactive union member is an Undefined Behavior. Using the first union member for reflection could lead to disaster if it is some character pointer. For example ostreaming `union {char* c; long long ll; } u; u.ll= 1;` will crash your program, as the active member is `ll` that holds `1` but we are trying to output a `char*`. This would cause an invalid pointer dereference.
|
||||
|
||||
Any attempt to reflect unions leads to a compile time error. In many cases a static assert is triggered that outputs the following message:
|
||||
|
||||
```
|
||||
error: static_assert failed "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
```
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ template <class Type>
|
||||
constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_union<Type>::value>*) noexcept {
|
||||
static_assert(
|
||||
!std::is_union<Type>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to flat_ reflect unions. It could lead to crashes (for example when attempting to output the union with inactive first `const char*` field)."
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
@@ -549,7 +549,7 @@ template <class T>
|
||||
auto tie_as_flat_tuple(T& lvalue) noexcept {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to flat_ reflect unions. It could lead to crashes (for example when attempting to output the union with inactive first `const char*` field)."
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
using type = std::remove_cv_t<T>;
|
||||
using tuple_type = internal_tuple_with_same_alignment_t<type>;
|
||||
@@ -564,7 +564,7 @@ template <class T>
|
||||
auto tie_as_tuple(T& val) noexcept {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. It could lead to crashes (for example when attempting to output the union with inactive first `const char*` field)."
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
static_assert(
|
||||
boost::pfr::detail::is_flat_refelectable<T>( std::make_index_sequence<boost::pfr::detail::fields_count<T>()>{} ),
|
||||
@@ -671,7 +671,7 @@ template <class T, class F, std::size_t... I>
|
||||
void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. It could lead to crashes (for example when attempting to output the union with inactive first `const char*` field)."
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
|
||||
/// Compile time error at this point means that you have called `for_each_field` or some other non-flat function or operator for a
|
||||
|
||||
@@ -142,7 +142,7 @@ template <class T>
|
||||
auto tie_or_value(T& val, std::enable_if_t<std::is_union< std::remove_reference_t<T> >::value>* = 0) noexcept {
|
||||
static_assert(
|
||||
sizeof(T) && false,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to flat_ reflect unions. It could lead to crashes (for example when attempting to output the union with inactive first `const char*` field)."
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
@@ -177,7 +177,7 @@ template <class T>
|
||||
auto tie_as_flat_tuple(T& t) {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to flat_ reflect unions. It could lead to crashes (for example when attempting to output the union with inactive first `const char*` field)."
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
auto rec_tuples = boost::pfr::detail::tie_as_tuple_recursively(
|
||||
boost::pfr::detail::tie_as_tuple_loophole_impl(t)
|
||||
@@ -194,7 +194,7 @@ template <class T>
|
||||
auto tie_as_tuple(T& val) noexcept {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. It could lead to crashes (for example when attempting to output the union with inactive first `const char*` field)."
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
return boost::pfr::detail::tie_as_tuple_loophole_impl(
|
||||
val
|
||||
@@ -205,7 +205,7 @@ template <class T, class F, std::size_t... I>
|
||||
void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. It could lead to crashes (for example when attempting to output the union with inactive first `const char*` field)."
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
std::forward<F>(f)(
|
||||
boost::pfr::detail::tie_as_tuple_loophole_impl(t)
|
||||
|
||||
@@ -50,7 +50,7 @@ template <class T, class F, std::size_t... I>
|
||||
void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. It could lead to crashes (for example when attempting to output the union with inactive first `const char*` field)."
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
std::forward<F>(f)(
|
||||
detail::tie_as_tuple(t)
|
||||
|
||||
@@ -1030,7 +1030,7 @@ template <class T>
|
||||
constexpr auto tie_as_tuple(T& val) noexcept {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. It could lead to crashes (for example when attempting to output the union with inactive first `const char*` field)."
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
typedef size_t_<fields_count<T>()> fields_count_tag;
|
||||
return boost::pfr::detail::tie_as_tuple(val, fields_count_tag{});
|
||||
|
||||
@@ -70,7 +70,7 @@ template <class T>
|
||||
constexpr auto tie_as_tuple(T& val) noexcept {
|
||||
static_assert(
|
||||
!std::is_union<T>::value,
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. It could lead to crashes (for example when attempting to output the union with inactive first `const char*` field)."
|
||||
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||
);
|
||||
typedef size_t_<fields_count<T>()> fields_count_tag;
|
||||
return boost::pfr::detail::tie_as_tuple(val, fields_count_tag{});
|
||||
|
||||
Reference in New Issue
Block a user