Modern vehicles exchange and store large amounts of data. Embedded systems, automotive software platforms, and digital maps all depend on binary formats that use storage efficiently and define exactly where each value belongs. Writing the code that reads and writes these formats by hand takes time and can introduce errors.
zserio addresses this challenge by generating serialization code from a schema. Developers describe the data structure once, and zserio produces the code needed to read, write, and validate that data in C++, Java, Python, and other supported languages.

The established zserio C++ generator targets C++11 and is used in production across the NDS ecosystem. The zserio C++17 extension is its modern successor. It is a separate generator with a redesigned API, built around one central idea: keep the data itself separate from the rules used to interpret it. This article explains why that change was needed, how the new design works, and what development teams should consider before adopting it.
The C++11 generator is stable and proven. The challenge is backward compatibility. Over time, users asked for a more intuitive application programming interface (API), support for newer C++ features, and solutions to recurring usability problems. Introducing those changes directly into the existing generator would have broken applications that already depended on its current API.
The zserio C++ Special Interest Group therefore reconsidered the design from the ground up. Member companies from the NDS ecosystem contributed problems they had encountered in production code. The group developed several possible designs and evaluated them using shared schemas and real map data.
The result was the Data View design. The zserio C++17 extension turns that design into a complete generator. Its API is intentionally different from the C++11 version, so the developers could improve the structure without being limited by backward compatibility.
A zserio schema can define a parameterized type, a data structure whose exact layout depends on another value. In the following example, the value called version determines whether extraParam is present:
struct Item(uint32 version)
{
uint16 param;
uint32 extraParam if version >= 10;
};
To interpret this structure correctly, the generated code needs both the stored field values and the version parameter. The C++11 and C++17 generators handle that relationship differently.
The C++11 generator creates one class for each schema type. That class contains the data fields, schema parameters, getters and setters, and the code for reading and writing the data. It also stores the parameters inside every object, together with information about whether they have been supplied.
This leads to two-phase initialization. First, the application creates the object. Then it must call initialize() to provide the parameters. If that second step is missed, the problem appears only when the application runs. Parameters for nested structures are also stored through raw pointers, so the parent object must remain available for as long as the child uses it. The type system does not make that dependency obvious.
The C++17 design treats the parameter differently. The version value already exists in the data stream, so the data object does not need to store a second copy. The parameter is required only when the application interprets the data, for example when it validates, serializes, or runs a function defined in the schema.
For this reason, the C++17 generator separates the original all-in-one class into three parts:
The difference is visible in the generated API:
// C++11 generator
Item item;
item.setParam(0xAA);
item.setExtraParam(0xBB);
item.initialize(version); // two-phase initialization -
item.write(writer); // forgetting it is a runtime error
// C++17 generator
Item item(0xAA, 0xBB); // just data
zserio::View view(item, version); // parameters bind here
auto buffer = zserio::serialize(view); // validates and writes
In practice, this separation brings several changes:
Because a view borrows the data, the application must keep that data available while the view is in use. When an owning object is more convenient, zserio::DataView combines the data and its view in one self-contained object.
Map engineering teams cannot always adopt the newest C++ standard as soon as it appears. They depend on the compilers available for their target platforms and on functional-safety guidance that covers the selected language version. MISRA C++ 2023 supports C++17, which gave the project an established guideline set for moving beyond C++11.
Moving to C++17 also allows the runtime to use features from the standard library instead of maintaining custom versions of similar concepts. The main changes include:
The extension also changes how zserio templates are represented. A zserio template defines a reusable schema structure. The C++11 generator creates a separate class for every use of that template. The C++17 generator instead produces a native C++ template, such as template <typename T>, so the generic structure remains generic in the generated code.
To make this possible, the runtime provides a dedicated C++ type for each zserio built-in type, including zserio::UInt16, zserio::VarUInt, and zserio::Float16. This distinction matters because two zserio types can use the same underlying C++ type while still representing different schema meanings. For example, bit:31 and uint32 can both use uint32_t in C++, but the generator still needs to tell them apart. Implicit conversions allow developers to use these wrapper types in normal arithmetic, and the Special Interest Group benchmarked them against native types before adopting the design.
The Data View design is the central change, but the C++17 extension is intended as a complete generator rather than a limited demonstration. It includes:
Serialization code can become part of a safety-relevant automotive system. The C++17 extension is therefore tested across g++, clang, MinGW, and MSVC on supported 32-bit and 64-bit targets.
The build process treats compiler warnings as errors and uses sanitizers, clang-tidy, SonarCloud analysis, and a strict runtime code-coverage requirement. The complete test suite also runs with every allocator mode and with runtime type information (RTTI) disabled. Generated headers refuse to compile with an incompatible runtime version, which prevents a version mismatch from being discovered only after deployment.
The design follows the MISRA C++ 2023 guidelines. The small number of deliberate deviations is documented in the C++17 Design Document, allowing engineering teams to review both the generated-code structure and the reasoning behind the design before they adopt it.
The C++17 API is intentionally incompatible with the C++11 API, and both generators remain available. Moving an existing application is therefore a port, not a routine upgrade: developers must adapt their application code to the new API. A stable project using the C++11 generator does not need to move simply because the new generator exists.
The C++17 extension is most relevant when:
The C++17 extension is ready to use, but it is still younger than the C++11 generator. The established generator has benefited from years of production use, while the newer extension has not yet accumulated the same level of operational experience. Teams adopting it today should take that difference in maturity into account.
Its early stage also gives users a chance to influence how the extension develops. If you test it, even by running the generator on an existing schema and reviewing the generated code, share what worked well and what created friction. Report problems or suggestions through the zserio C++17 issue tracker so the community can discuss and improve them.
The zserio C++17 extension is available under the BSD 3-Clause license and is developed openly in the zserio C++17 repository. Version 1.2.0 is designed for zserio core 2.18.1. It supports 64-bit and 32-bit Linux and 64-bit Windows with g++, clang, MinGW, and MSVC.
Using the bundles provided with each release, developers can generate C++17 code with one command:
java -jar zserio.jar schema_name.zs -cpp17 output_directory_name
Start with the project README for command-line options and notes about generated code. Use the runtime API documentation as the reference when integrating the generated code into an application.
Back to news →