A lightweight C++20 serialization framework

zpp::bits

Build Status

A modern C++20 binary serialization library, with just one header file.

This library is a successor to zpp::serializer. The library tries to be simpler for use, but has more or less similar API to its predecessor.

Motivation

Provide a single, simple header file, that would enable one to:

  • Enable save & load any STL container / string / utility into and from a binary form, in a zero overhead approach.
  • Enable save & load any object, by adding only a few lines to any class, without breaking existing code.
  • Enable save & load the dynamic type of any object, by a simple one-liner.

The Difference From zpp::serializer

  • It is simpler
  • Performance improvements
  • Almost everything is constexpr
  • More flexible with serialization of the size of variable length types, opt out from serializing size.
  • Opt-in for zpp::throwing if header is found.
  • More friendly towards freestanding (no exception runtime support).
  • Breaks compatibility with anything lower than C++20 (which is why the original library is left intact).
  • Better naming for utility classes and namespaces, for instance zpp::bits is more easily typed than zpp::serializer.
  • For now, dropped support for polymorphic serialization, seeking a more modern way to do it.

Contents

  • For most types, enabling serialization is just one line. Here is an example of a person class with name and age:
struct person
{
    // Add this line to your class with the number of members:
    using serialize = zpp::bits::members<2>; // Two members

    std::string name;
    int age{};
};

Most of the time types we serialize can work with structured binding, and this library takes advantage of that, but you need to provide the number of members in your class for this to work using the method above.

  • If your data members or default constructor are private, you need to become friend with zpp::bits::access like so:
struct private_person
{
    // Add this line to your class.
    friend zpp::bits::access;
    using serialize = zpp::bits::members<2>;

private:
    std::string name;
    int age{};
};
  • To enable save & load of any object, even ones without structured binding, add the following lines to your class
    constexpr static auto serialize(auto & archive, auto & self)
    {
        return archive(self.object_1, self.object_2, ...);
    }

Note that object_1, object_2, ... are the non-static data members of your class.

  • Here is the example of a person class again with explicit serialization function:
struct person
{
    constexpr static auto serialize(auto & archive, auto & self)
    {
        return archive(self.name, self.age);
    }

    std::string name;
    int age{};
};
  • Example how to serialize the person into and from a vector of bytes:
// The `data_in_out` utility function creates a vector of bytes, the input and output archives
// and returns them so we can decompose them easily in one line using structured binding like so:
auto [data, in, out] = zpp::bits::data_in_out();

// Serialize a few people:
out(person{"Person1", 25}, person{"Person2", 35});

// Define our people.
person p1, p2;

// We can now deserialize them either one by one `in(p1)` `in(p2)`, or together, here
// we chose to do it together in one line:
in(p1, p2);

This example almost works, we are being warned that we are discarding the return value. we need to check for errors, the library offers multiple ways to do so - a return value based, exception based, or zpp::throwing based.

The return value based way for being most explicit, or if you just prefer return values:

auto [data, in, out] = zpp::bits::data_in_out();

auto result = out(person{"Person1", 25}, person{"Person2", 35});
if (failure(result)) {
    // `result` is implicitly convertible to `std::errc`.
    // handle the error or return/throw exception.
}

person p1, p2;

result = in(p1, p2);
if (failure(result)) {
    // `result` is implicitly convertible to `std::errc`.
    // handle the error or return/throw exception.
}

The exceptions based way using .or_throw() (read this as "succeed or throw" - hence or_throw()):

int main()
{
    try {
        auto [data, in, out] = zpp::bits::data_in_out();

        // Check error using `or_throw()` which throws an exception.
        out(person{"Person1", 25}, person{"Person2", 35}).or_throw();

        person p1, p2;

        // Check error using `or_throw()` which throws an exception.
        in(p1, p2).or_throw();

        return 0;
    } catch (const std::exception & error) {
        std::cout << "Failed with error: " << error.what() << '\n';
        return 1;
    } catch (...) {
        std::cout << "Unknown error\n";
        return 1;
    });
}

Another option is zpp::throwing it turns into two simple co_awaits, to understand how to check for error we provide a full main function:

int main()
{
    return zpp::try_catch([]() -> zpp::throwing<int> {
        auto [data, in, out] = zpp::bits::data_in_out();

        // Check error using `co_await`, which suspends the coroutine.
        co_await out(person{"Person1", 25}, person{"Person2", 35});

        person p1, p2;

        // Check error using `co_await`, which suspends the coroutine.
        co_await in(p1, p2);

        co_return 0;
    }, [](zpp::error error) {
        std::cout << "Failed with error: " << error.message() << '\n';
        return 1;
    }, [](/* catch all */) {
        std::cout << "Unknown error\n";
        return 1;
    });
}
  • Constructing input and output archives together and separately from data:
// Create both a vector of bytes, input and output archives.
auto [data, in, out] = zpp::bits::data_in_out();

// Create just the input and output archives, and bind them to the
// existing vector of bytes.
std::vector<std::byte> data;
auto [in, out] = zpp::bits::in_out(data);

// Create all of them separately
std::vector<std::byte> data;
zpp::bits::in in(data);
zpp::bits::out out(data);

// When you need just data and in/out
auto [data, in] = zpp::bits::data_in();
auto [data, out] = zpp::bits::data_out();
  • Archives can be constructed from either one of the byte types:
// Either one of these work with the below.
std::vector<std::byte> data;
std::vector<char> data;
std::vector<unsigned char> data;
std::string data;

// Automatically works with either `std::byte`, `char`, `unsigned char`.
zpp::bits::in in(data);
zpp::bits::out out(data);

You can also use fixed size data objects such as std::array and view types such as std::span similar to the above. You just need to make sure there is enough size since they are non resizable.

  • When using a vector, it automatically grows to the right size, however, you can also output and input from a span, in which case your memory size is limited by the memory span:
zpp::bits::in in(std::span{pointer, size});
zpp::bits::out out(std::span{pointer, size});
  • Query the position of in and out using position(), in other words the bytes read and written respectively:
std::size_t bytes_read = in.position();
std::size_t bytes_written = out.position();
  • Reset the position backwards or forwards, or to the beginning:
in.reset(); // reset to beginning.
in.reset(position); // reset to position.

out.reset(); // reset to beginning.
out.reset(position); // reset to position.
  • Serializing STL containers and strings, first stores a 4 byte size, then the elements:
std::vector v = {1,2,3,4};
out(v);
in(v);

The reason why the default size type is of 4 bytes (i.e std::uint32_t) is that most programs almost never reach a case of a container being more than ~4 billion items, and it may be unjust to pay the price of 8 bytes size by default.

  • For specific size types that are not 4 bytes, use zpp::serializer::size_is<SizeType>():
std::vector<int> v = {1,2,3,4};
out(zpp::bits::sized<std::uint16_t>(v));
in(zpp::bits::sized<std::uint16_t>(v));

Make sure that the size type is large enough for the serialized object, otherwise less items will be serialized, according to conversion rules of unsigned types.

  • You can also choose to not serialize the size at all, like so:
std::vector<int> v = {1,2,3,4};
out(zpp::bits::unsized(v));
in(zpp::bits::unsized(v));
  • Serialization using argument dependent lookup is also possible, using both the automatic member serialization way or with fully defined serialization functions.

With automatic member serialization:

namespace my_namespace
{
struct adl
{
    int x;
    int y;
};

constexpr auto serialize(const adl & adl) -> zpp::bits::members<2>;
} // namespace my_namespace

With fully defined serialization functions:

namespace my_namespace
{
struct adl
{
    int x;
    int y;
};

constexpr auto serialize(auto & archive, adl & adl)
{
    return archive(adl.x, adl.y);
}

constexpr auto serialize(auto & archive, const adl & adl)
{
    return archive(adl.x, adl.y);
}
} // namespace my_namespace
  • If you know your type is serializaeble just as raw bytes, you can opt in and optimize its serialization to a mere memcpy:
struct point
{
    int x;
    int y;

    constexpr static auto serialize(auto & archive, auto & self)
    {
        // Serialize as bytes, instead of serializing each
        // member separately. The overall result is the same, but this may be
        // faster sometimes.
        return archive(zpp::bits::as_bytes(self));
    }
};

It's also possible to do this directly from a vector or span of trivially copyable types, this time we use bytes instead of as_bytes because we convert the contents of the vector to bytes rather than the vector object itself (the data the vector points to rather than the vector object):

std::vector<point> points;
out(zpp::bits::bytes(points));
in(zpp::bits::bytes(points));

However in this case the size is not serialized, this may be extended in the future to also support serializing the size similar to other view types. If you need to serialize as bytes and want the size, as a workaround it's possible to cast to std::span<std::byte>.

  • This should cover most of the basic stuff, more documentation may come in the future.

Final Words

I wish that you find this library useful. Please feel free to submit any issues, make suggestions for improvements, etc.

Comments
  • How to use RPC in real world?

    How to use RPC in real world?

    Hi! I like your library! But your RPC framework very strange. How to use it in real world? There are no any info how to use some transport, for example sockets. Could you please add some examples?

  • Failed to compile serialization of std::queue

    Failed to compile serialization of std::queue

    zpp_bits version: 4.4.10

    The simplified code:

    class SoaBase {
     public:
      constexpr static auto serialize(auto &archive, SoaBase &self) {
        return archive(self.recycled_indexes_);
      }
    
      std::queue<uint32_t> recycled_indexes_;
    };
    

    The error message:

    C:\Libraries\zpp_bits\zpp_bits.h(1378): error C2672: 'zpp::bits::access::visit_members': no matching overloaded function found
    C:\Libraries\zpp_bits\zpp_bits.h(2524): note: see reference to function template instantiation 'decltype(auto) zpp::bits::visit_members<std::queue<uint32_t,std::deque<uint32_t,std::allocator<std::seed_seq::result_type>>>&,zpp::bits::in<_ReturnType,zpp::bits::options::alloc_limit<1073741824>>::serialize_one::<lambda_1>>(_T0,_T1 &&)' being compiled
            with
            [
                _T0=std::queue<uint32_t,std::deque<uint32_t,std::allocator<std::seed_seq::result_type>>> &,
                _T1=zpp::bits::in<_ReturnType,zpp::bits::options::alloc_limit<1073741824>>::serialize_one::<lambda_1>
            ]
    ...
    
  • Compiling with MSVC results in a

    Compiling with MSVC results in a "fatal error C1001: Internal compiler error"

    When I compile the following code with Visual Studio 2022 Preview 5, I get an error

    template <typename Container>
      static auto parse(Container&& buf, dos_header& header) -> std::error_code {
        if (buf.size() < size) {
          return make_error_code(deep::parser::parse_error::too_small_buffer);
        }
    
        auto in = zpp::bits::input(buf); // this is the line that causes the error (probably)
        in(header);
    
        if (header.e_magic != magic) {
          return deep::parser::make_error_code(
              deep::parser::parse_error::invalid_magic_number);
        }
    
        return {};
      }
    

    The error I get: fatal error C1001: Internal compiler error. (compiler file 'D:\a\_work\1\s\src\vctools\Compiler\CxxFE\sl\p1\c\module\parse-tree-resolve.cpp', line 736) To work around this problem, try simplifying or changing the program near the locations listed above.

  • Cannot compile using Visual Studio 2019

    Cannot compile using Visual Studio 2019

    It seems like Visual Studio has trouble compiling the file. I get a fatal error C1004: unexpected end-of-file found when I include zpp_bits.h. Also Visual Studio's IntelliSense breaks completely for any file that has #include "zpp_bits.h" for me.

    #include "zpp_bits.h"
    #include <fstream>
    #include <vector>
    int main() {
        struct Test {
            using serialize = zpp::bits::members<3>;
            int i = 1, j = 2, k = 3;
        };
        std::vector<Test> tests;
        tests.resize(10);
    
        std::vector<char> data;
        zpp::bits::out out(data);
        auto result = out(tests);
    
        std::ofstream save_file("test.txt", std::ios::binary);
        save_file.write(data.data(), data.size());
        save_file.close();
    
        return 0;
    }
    

    When I comment out the line auto result = out(tests); the error disappears and it builds successfully.

    I also tried #define ZPP_BITS_INLINE_MODE 0 but that wasn't the problem.

  • What the format of serialized object?

    What the format of serialized object?

    Could you provide a doc describe the format of a serialized object, how to arrange the members in memory? Another question: https://github.com/eyalz800/zpp_bits/blob/main/zpp_bits.h#L1860 What the algorithm of enlarge_for, no UT for it.

  • How to implement serialization function of derived class?

    How to implement serialization function of derived class?

    class MyDerived: public MyBase {
      constexpr static auto serialize(auto &archive, auto &self) {
        MyBase::serialize(archive, self);
        return archive(self.member1, self.member2);
      }
    }
    

    Is this code correct? Will it cause some errors not to be handled? Maybe we should add a piece of document on how to serialize derived class gracefully?

  • problem with a recursive structure

    problem with a recursive structure

    Hi, I define a struct which represents a tree.

    struct Node {
        std::vector<std::pair<uint32_t, std::shared_ptr<Node>>> children;
        std::vector<uint32_t> word;
    };
    

    But gcc reports an error.

    zpp_bits.h:1817:20: error: function 'serialize_many<std::shared_ptr<Node> &>' with deduced return type cannot be used before it is defined
    return serialize_many(items...);
    

    Does it mean that recursion is not yet supported or something like that?

  • MSVC compile error

    MSVC compile error

    • vs2019 latest
    • c++20
    • code
    struct person
    {
    	std::string name;
    	int age{};
    };
    int main() {
    	auto [data, in, out] = zpp::bits::data_in_out();
    
    	// Serialize a few people:
    	out(person{ "Person1", 25 }, person{ "Person2", 35 });
    
    	// Define our people.
    	person p1, p2;
    
    	// We can now deserialize them either one by one `in(p1)` `in(p2)`, or together, here
    	// we chose to do it together in one line:
    	in(p1, p2);
    
    
    	return 0;
    }
    
    • output
    Build started...
    1>------ Build started: Project: ConsoleApplication1, Configuration: Release Win32 ------
    1>ConsoleApplication1.cpp
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(91,65): warning C4003: not enough arguments for function-like macro invocation 'max'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(97,82): warning C4003: not enough arguments for function-like macro invocation 'max'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(471,54): warning C4003: not enough arguments for function-like macro invocation 'max'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(479,50): warning C4003: not enough arguments for function-like macro invocation 'max'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(471,54): error C2589: '(': illegal token on right side of '::'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(468,50): message : This diagnostic occurred in the compiler generated function 'size_t zpp::bits::traits::variant_impl<Variant<Types...>>::index(_T0 &&)'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(529): message : see reference to class template instantiation 'zpp::bits::traits::variant_impl<Variant<Types...>>' being compiled
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(658,50): warning C4003: not enough arguments for function-like macro invocation 'max'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(658,50): error C2589: '(': illegal token on right side of '::'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(668,50): warning C4003: not enough arguments for function-like macro invocation 'max'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(668,50): error C2589: '(': illegal token on right side of '::'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(1140,52): warning C4003: not enough arguments for function-like macro invocation 'max'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(1151,52): warning C4003: not enough arguments for function-like macro invocation 'max'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(1161,52): warning C4003: not enough arguments for function-like macro invocation 'max'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(1173,52): warning C4003: not enough arguments for function-like macro invocation 'max'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(1140,52): error C2589: '(': illegal token on right side of '::'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(201,27): message : This diagnostic occurred in the compiler generated function 'auto zpp::bits::access::number_of_members(void)'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(1917,61): warning C4003: not enough arguments for function-like macro invocation 'max'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(1917,61): error C2589: '(': illegal token on right side of '::'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(1889,36): message : This diagnostic occurred in the compiler generated function 'zpp::bits::errc zpp::bits::basic_out<ByteView,Options...>::enlarge_for(_T0)'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(2344): message : see reference to class template instantiation 'zpp::bits::basic_out<ByteView,Options...>' being compiled
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(2675,65): warning C4003: not enough arguments for function-like macro invocation 'max'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(2675,65): error C2589: '(': illegal token on right side of '::'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(2645,5): message : This diagnostic occurred in the compiler generated function 'zpp::bits::errc zpp::bits::in<ByteView,Options...>::serialize_one(_T0 &&)'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(3050): message : see reference to class template instantiation 'zpp::bits::in<ByteView,Options...>' being compiled
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(4855,62): warning C4003: not enough arguments for function-like macro invocation 'max'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(5052,53): warning C4003: not enough arguments for function-like macro invocation 'max'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(4855,62): error C2589: '(': illegal token on right side of '::'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(5100): message : see reference to class template instantiation 'zpp::bits::pb<Options...>' being compiled
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(4855,1): error C2059: syntax error: ')'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(97,82): error C2589: '(': illegal token on right side of '::'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(97,82): error C2059: syntax error: ')'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(97,26): error C2947: expecting '>' to terminate template-argument-list, found '>'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(4761,35): error C2976: 'zpp::bits::protocol': too few template arguments
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(99): message : see declaration of 'zpp::bits::protocol'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(4712,5): message : This diagnostic occurred in the compiler generated function 'zpp::bits::errc zpp::bits::pb<Options...>::serialize_one(_T0 &,_T1 &)'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(4860,43): error C2589: '(': illegal token on right side of '::'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(4852,36): message : This diagnostic occurred in the compiler generated function 'zpp::bits::errc zpp::bits::pb<Options...>::operator ()(_T0 &,_T1 &,size_t) const'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(4990,35): error C2976: 'zpp::bits::protocol': too few template arguments
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(99): message : see declaration of 'zpp::bits::protocol'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(4949,43): message : This diagnostic occurred in the compiler generated function 'auto zpp::bits::pb<Options...>::deserialize_field(_T0 &,zpp::bits::pb<Options...>::wire_type,_T1 &)'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(5052,53): error C2589: '(': illegal token on right side of '::'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(4949,43): message : This diagnostic occurred in the compiler generated function 'auto zpp::bits::pb<Options...>::deserialize_field(_T0 &,zpp::bits::pb<Options...>::wire_type,_T1 &)'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(5102,21): error C2976: 'zpp::bits::protocol': too few template arguments
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(99): message : see declaration of 'zpp::bits::protocol'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(5104,67): warning C4003: not enough arguments for function-like macro invocation 'max'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(668): error C2062: type 'unknown-type' unexpected
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(668,1): error C2059: syntax error: ')'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(2440,27): error C2182: 'allocation_limit': illegal use of type 'void'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(2441,1): error C2440: 'initializing': cannot convert from 'void' to 'const int'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(2441,40): message : Expressions of type void cannot be converted to other types
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(1818,27): error C2182: 'allocation_limit': illegal use of type 'void'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(2348): message : see reference to class template instantiation 'zpp::bits::basic_out<ByteView>' being compiled
    1>        with
    1>        [
    1>            ByteView=std::vector<std::byte,std::allocator<std::byte>>
    1>        ]
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(3090): message : see reference to class template instantiation 'zpp::bits::out<std::vector<ByteType,std::allocator<ByteType>>>' being compiled
    1>        with
    1>        [
    1>            ByteType=std::byte
    1>        ]
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(1818,1): error C2440: 'initializing': cannot convert from 'void' to 'const int'
    1>E:\test\zpp_bits-4.4.10\zpp_bits.h(1818,77): message : Expressions of type void cannot be converted to other types
    1>C:\Users\user123\source\repos\vs2019\ConsoleApplication1\ConsoleApplication1.cpp(16,5): warning C4834: discarding return value of function with 'nodiscard' attribute
    1>C:\Users\user123\source\repos\vs2019\ConsoleApplication1\ConsoleApplication1.cpp(23,4): warning C4834: discarding return value of function with 'nodiscard' attribute
    1>Done building project "ConsoleApplication1.vcxproj" -- FAILED.
    
  • can't serialize empty tuple

    can't serialize empty tuple

    First this is a great library.

    Issue: Serializing empty tuple result in compile time error. It would be nice if it didn't like it doesn't for e.g. empty vector.

    std::tuple<> t; auto [m,out] = zpp::bits::data_out(); out(t);

  • zpp_bits nukes intellisense

    zpp_bits nukes intellisense

    This is likely to be a problem with intellisense, but including zpp_bits.h seems to cause intellisense to run into issues.

    Is there any reccomended workaround for this until a day when intellisense is fixed?

    Unclear if pImpl is possible given that "using serialize = zpp::bits::members<3>" requires #include <zpp_bits/zpp_bits.h>

  • Testing at runtime if archive is loading or saving

    Testing at runtime if archive is loading or saving

    Hi,

    Let's suppose I need to perform additional actions after the class members are loaded. How to determine if the Archive passed to static void serialize(Archive & archive, Self & self) member template method is loading or saving one?

    template <typename Archive, typename Self>
    static void serialize(Archive & archive, Self & self)
    {
         archive(self.width, self.height);
    
         if (archive.is_loading())
             self.allocate(self.width, self.height);
    }
    
  • Internal Compiler Error - MSVC Latest (14.34.31933)

    Internal Compiler Error - MSVC Latest (14.34.31933)

    Microsoft recently released an update to VS2022 that broke compilation for zpp_bits

    Reproduction here (14.34.31931-Pre): https://godbolt.org/z/szx4PTMM8

    Is there any workarounds or fixes?

    I have not opened a ticket with microsoft since I would be unable to provide a minimal reproduction but it may be worth looking into.

Serialization framework for Unreal Engine Property System that just works!

DataConfig Serialization framework for Unreal Engine Property System that just works! Unreal Engine features a powerful Property System which implemen

Nov 27, 2022
Your binary serialization library

Bitsery Header only C++ binary serialization library. It is designed around the networking requirements for real-time data delivery, especially for ga

Dec 1, 2022
Cap'n Proto serialization/RPC system - core tools and C++ library
Cap'n Proto serialization/RPC system - core tools and C++ library

Cap'n Proto is an insanely fast data interchange format and capability-based RPC system. Think JSON, except binary. Or think Protocol Buffers, except

Dec 1, 2022
A C++11 library for serialization
A C++11 library for serialization

cereal - A C++11 library for serialization cereal is a header-only C++11 serialization library. cereal takes arbitrary data types and reversibly turns

Dec 2, 2022
Fast Binary Encoding is ultra fast and universal serialization solution for C++, C#, Go, Java, JavaScript, Kotlin, Python, Ruby, Swift

Fast Binary Encoding (FBE) Fast Binary Encoding allows to describe any domain models, business objects, complex data structures, client/server request

Dec 1, 2022
FlatBuffers: Memory Efficient Serialization Library

FlatBuffers FlatBuffers is a cross platform serialization library architected for maximum memory efficiency. It allows you to directly access serializ

Nov 27, 2022
Yet Another Serialization
Yet Another Serialization

YAS Yet Another Serialization - YAS is created as a replacement of boost.serialization because of its insufficient speed of serialization (benchmark 1

Nov 18, 2022
Binary Serialization

Binn Binn is a binary data serialization format designed to be compact, fast and easy to use. Performance The elements are stored with their sizes to

Nov 24, 2022
An implementation of the MessagePack serialization format in C / msgpack.org[C]

CMP CMP is a C implementation of the MessagePack serialization format. It currently implements version 5 of the MessagePack Spec. CMP's goal is to be

Nov 17, 2022
MPack - A C encoder/decoder for the MessagePack serialization format / msgpack.org[C]

Introduction MPack is a C implementation of an encoder and decoder for the MessagePack serialization format. It is: Simple and easy to use Secure agai

Nov 30, 2022
Simple C++ 20 Serialization Library that works out of the box with aggregate types!

BinaryLove3 Simple C++ 20 Serialization Library that works out of the box with aggregate types! Requirements BinaryLove3 is a c++20 only library.

Sep 2, 2022
Zmeya is a header-only C++11 binary serialization library designed for games and performance-critical applications

Zmeya Zmeya is a header-only C++11 binary serialization library designed for games and performance-critical applications. Zmeya is not even a serializ

Nov 2, 2022
CppSerdes is a serialization/deserialization library designed with embedded systems in mind
CppSerdes is a serialization/deserialization library designed with embedded systems in mind

A C++ serialization/deserialization library designed with embedded systems in mind

Nov 5, 2022
Header-only library for automatic (de)serialization of C++ types to/from JSON.

fuser 1-file header-only library for automatic (de)serialization of C++ types to/from JSON. how it works The library has a predefined set of (de)seria

Oct 20, 2022
Yet Another Serialization
Yet Another Serialization

YAS Yet Another Serialization - YAS is created as a replacement of boost.serialization because of its insufficient speed of serialization (benchmark 1

Sep 7, 2021
C++17 library for all your binary de-/serialization needs

blobify blobify is a header-only C++17 library to handle binary de-/serialization in your project. Given a user-defined C++ struct, blobify can encode

Oct 20, 2022
universal serialization engine

A Universal Serialization Engine Based on compile-time Reflection iguana is a modern, universal and easy-to-use serialization engine developed in c++1

Dec 2, 2022
Yet another JSON/YAML/BSON serialization library for C++.
Yet another JSON/YAML/BSON serialization library for C++.

ThorsSerializer Support for Json Yaml Bson NEW Benchmark Results Conformance mac linux Performance max linux For details see: JsonBenchmark Yet anothe

Oct 27, 2022
Cista is a simple, high-performance, zero-copy C++ serialization & reflection library.

Simple C++ Serialization & Reflection. Cista++ is a simple, open source (MIT license) C++17 compatible way of (de-)serializing C++ data structures. Si

Dec 1, 2022