pfr
pfr copied to clipboard
Can packed structures be supported?
I noticed that packed structures are not supported, while it is not mentioned in documentation.
For example:
struct __attribute__ ((packed)) A
{
int x;
int z;
bool y;
};
The error message is following:
static_assert(sizeof(U) == sizeof(S), "====================> Boost.PFR: Member sequence does not indicate correct size for struct type! Maybe the user-provided type is not a SimpleAggregate?");
~~~~~~~~~~^~~~~~~~~~~~
Link: https://godbolt.org/z/Exo16Mods
However, the class should be an Aggregate, as
An aggregate is an array or a class (clause 9) with no user-declared constructors (12.1), no private or protected non-static data members (clause 11), no base classes (clause 10), and no virtual functions (10.3).
Is there a technical obstacle on adding packed structures?
Please note that __attribute__((packed)) is a gcc extension, so what does the the c++ standard say about aggregates is irrelevant here. Unfortunately, gcc's documentations is pretty terse on this subject: https://gcc.gnu.org/onlinedocs/gcc-11.2.0/gcc/Common-Type-Attributes.html
However, if you set -std=c++17, you get a different error:
/opt/compiler-explorer/libs/boost_1_77_0/boost/pfr/detail/core17_generated.hpp:58:57: error: cannot bind packed field 'a' to 'int&'
58 | return ::boost::pfr::detail::make_tuple_of_references(a,b,c);
| ^
Which reveals a deeper problem, namely that gcc doesn't allow int& x = a.x;
Clang actually allows this (your example compiles with clang in c++17), and even gcc allows int* x = &a.x; with a warning, but you shouldn't do that either, as dereferencing an unaligned pointer is undefined behavior. Packed structs should be treated the same as bitfields, you have to access the members through the structure as you can't get pointers/references to the members. (Unless there's yet another gcc extension, that allows you to mark a pointer as unaligned).
By the way, bitfields don't work either.
It is good that gcc forbids the creating reference to unaligned structure field. Clang does not, and this would likely result with ub on some platforms.
The assertion from the loophole implementation makes perfect sense, and I think we may need a similar assertion for the cpp17 structure binding implementation.
Given that there is no way to obtain a reference to custom aligned field, it's good to have an option access members by value.
Interestingly, the gcc does not give a warning for the corresponding structure_to_tuple method. Logically in this case there is no reference returned outside, but there is some base classes magic in detail/sequence_tuple.hpp which I didn't get. Aren't they accessing by reference in the middle?
Update:
So the structure_to_tuple works because it binds by constant reference (actually it's happening in tie_as_tuple()), and in case of gcc it seem to copy the value. See small example here https://godbolt.org/z/1f9nKx4bd
also see the following clang bug https://bugs.llvm.org/show_bug.cgi?id=28571