Personally, I just write serialization functions using fwrite/fread/write/read, but I’ve used projects which depend on it.
Instead of relying on serialization of existing data structures I actually try to use more general data structures that already exist in a single span of memory.
Then serialization is just a matter of writing them out from start to finish, or allocating them in a memory mapped file.
* libnop uses a macro called NOP_STRUCTURE to create its key-value pairs.
* Cereal has a macro called CEREAL_NVP.
* Boost.Fusion has BOOST_FUSION_ADAPT_ASSOC_STRUCT
* Boost.Hana has BOOST_HANA_ADAPT_STRUCT
* Boost.Serialization has BOOST_SERIALIZATION_NVP
...all these things work the same way to get reflection
Don't forget that libnop also has NOP_EXTERNAL_STRUCTURE (and friends) to decouple the annotation from the structure definition. This is handy when you have a C ABI with C++ internal implementation. I don't recall seeing a similar facility in other libraries.