title: C++ Serialization Guide sidebar_position: 0 id: serialization_index license: | Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Apache Fory™ is a blazing fast multi-language serialization framework powered by JIT compilation and zero-copy techniques, providing up to ultra-fast performance while maintaining ease of use and safety.
The C++ implementation provides high-performance serialization with compile-time type safety using modern C++17 features and template metaprogramming. It supports both xlang mode for cross-language payloads and native mode for C++-only payloads.
The C++ implementation supports both CMake and Bazel build systems.
When building with MSVC, configure your build system to pass /Zc:preprocessor.
The easiest way to use Fory is with CMake's FetchContent module:
cmake_minimum_required(VERSION 3.16) project(my_project LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) if(MSVC) add_compile_options(/Zc:preprocessor) endif() include(FetchContent) FetchContent_Declare( fory GIT_REPOSITORY https://github.com/apache/fory.git GIT_TAG v1.3.0 SOURCE_SUBDIR cpp ) FetchContent_MakeAvailable(fory) add_executable(my_app main.cc) target_link_libraries(my_app PRIVATE fory::serialization)
Then build and run:
mkdir build && cd build cmake .. -DCMAKE_BUILD_TYPE=Release cmake --build . --parallel ./my_app
Create a MODULE.bazel file in your project root:
module( name = "my_project", version = "1.0.0", ) bazel_dep(name = "rules_cc", version = "0.1.1") bazel_dep(name = "fory", version = "1.3.0") git_override( module_name = "fory", remote = "https://github.com/apache/fory.git", commit = "v1.3.0", # Or use a specific commit hash for reproducibility )
Create a BUILD file for your application:
cc_binary( name = "my_app", srcs = ["main.cc"], deps = ["@fory//cpp/fory/serialization:fory_serialization"], )
When building with MSVC, add the conforming preprocessor option to your Bazel configuration:
# .bazelrc build --cxxopt=/Zc:preprocessor
Then build and run:
bazel build //:my_app bazel run //:my_app
For local development, you can use local_path_override instead:
bazel_dep(name = "fory", version = "1.3.0") local_path_override( module_name = "fory", path = "/path/to/fory", )
See the examples/cpp directory for complete working examples:
#include "fory/serialization/fory.h" #include <string> #include <vector> using namespace fory::serialization; // Define a struct struct Person { std::string name; int32_t age; std::vector<std::string> hobbies; bool operator==(const Person &other) const { return name == other.name && age == other.age && hobbies == other.hobbies; } }; FORY_STRUCT(Person, name, age, hobbies); int main() { // Create an xlang Fory instance auto fory = Fory::builder() .xlang(true) .track_ref(false) // Disable reference tracking for simple types .build(); // Register the type with a unique ID fory.register_struct<Person>(1); // Create an object Person person{"Alice", 30, {"reading", "coding"}}; // Serialize auto result = fory.serialize(person); if (!result.ok()) { // Handle error return 1; } std::vector<uint8_t> bytes = std::move(result).value(); // Deserialize auto deser_result = fory.deserialize<Person>(bytes); if (!deser_result.ok()) { // Handle error return 1; } Person decoded = std::move(deser_result).value(); assert(person == decoded); return 0; }
To include base-class fields in a derived type, list FORY_BASE(Base) inside FORY_STRUCT. The base must define its own FORY_STRUCT so its fields can be referenced.
struct Base { int32_t id; FORY_STRUCT(Base, id); }; struct Derived : Base { std::string name; FORY_STRUCT(Derived, FORY_BASE(Base), name); };
Use xlang mode for cross-language payloads and schemas shared with other Fory implementations. Xlang mode is the default C++ wire mode, and C++ examples that use it set .xlang(true) explicitly so the mode choice is visible.
Use native mode for C++-only traffic. Native mode is selected with .xlang(false) and keeps C++ object serialization in C++-native form. It is optimized for C++ types and avoids portable xlang type-mapping constraints when the payload never leaves C++. Compatible mode is enabled by default. Set .compatible(false) only when every reader and writer uses the same C++ schema and you want faster serialization and smaller size.
See Xlang Serialization for C++ xlang registration and interoperability rules, and Native Serialization for C++-only payloads.
Apache Fory™ C++ provides two variants for different threading needs:
// Single-threaded Fory - fastest, NOT thread-safe auto fory = Fory::builder().xlang(true).build();
// Thread-safe Fory - uses context pools auto fory = Fory::builder().xlang(true).build_thread_safe(); // Can be used from multiple threads safely std::thread t1([&]() { auto result = fory.serialize(obj1); }); std::thread t2([&]() { auto result = fory.serialize(obj2); });
Tip: Perform type registrations before spawning threads so every worker sees the same metadata.