It would be nice to not have two definitions in the spirit of DRY.
From a technical point of view it’s not a question of DRY. Two stucts with the same members in the same order but different padding are two distinct types. They have nothing in common because they may have different sizes and the members may live at different offsets. That’s as distinct as it gets.
So, separate definitions are unavoidable. To mitigate the source code duplication you could use the preprocessor. But you’re right of course, YAM is generally ugly, probably error prone, and altogether awful.
Instead take your preferred code generator and get rid of the duplication that way. The details depend on what that generator can do, of course. The most convenient solution for the programmer would be to write the non-packed struct manually. Something like this:
// header.hpp
namespace foo
{
struct Bar
{
// members ...
};
}
Possibly you need some kind of tag (macro? custom annotation?) to mark the types that need a packed version. Then let the code generator parse that header (possibly using libClang/libTooling) and generate the rest:
// header_packed.hpp
namespace foo::packed
{
struct __attribute__((packed)) Bar
{
// members ...
};
// conversion functions ...
}
The second best option is to write the relevant structs not in C++ but in some kind of DSL your code generator is familiar with and then generate all the C++ from that.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…