Engineering Core
ISB Vietnam's skilled software engineers deliver high-quality applications, leveraging their extensive experience in developing financial tools, business management systems, medical technology, and mobile/web platforms.

On C++26's Reflection

Table of Contents

Introduction

The C++26 standard is adding compile-time reflection to the language. This new feature enables C++ programs to inspect types, data members, and other program entities during compilation. As a result, developers can write more generic and less repetitive code for tasks such as serialization, validation, and code generation.

This article provides an overview of C++26 reflection, as currently supported in Clang’s experimental branches, and presents a practical example: serializing templated structures to JSON with minimal boilerplate.

What is Reflection?

Reflection refers to a language feature that allows a program to inspect or manipulate its own structure—such as types, data members, functions, or other entities—during program execution or compilation. This capability is widely available in languages like Java and C#, where programs can query and interact with type information at runtime (runtime reflection).

Historically, standard C++ has not provided built-in reflection. Developers have often relied on macros, manual coding, or third-party libraries to work around this limitation. As a result, tasks like serialization, validation, and automatic code generation have typically required repetitive boilerplate or external tools.

C++26 introduces compile-time reflection, which provides access to type and member information while the code is being compiled, with no runtime overhead. This approach enables the generation of highly generic and maintainable code for a wide range of metaprogramming scenarios.

The feature was introduced in paper P2996R13 and was voted into C++26 on June 25, 2025.

Using C++26 Reflection with Clang

At the time of writing, C++26 reflection is available in experimental branches of Clang, for example, Bloomberg's clang-p2996.

The core syntax involves:

  • Including <experimental/meta>.
  • Using the ^^ operator to reflect on a type.
  • Enumerating members with utilities like nonstatic_data_members_of.
  • "Splicing" members into code with obj.[:m:] syntax.

Example 1: Enumerating member names and values with reflection

Suppose we have the following two structures and wish to print their members’ names and values:

struct Point { int x = 1; int y = 2; };
struct Person { std::string name = "Bob"; int age = 30; };

Without reflection, one would probably have to write:

#include <iostream>
#include <string>
struct Point { int x = 1; int y = 2; };
struct Person { std::string name = "Bob"; int age = 30; };

int main() {
    Point pt;
    Person person;

    std::cout << "x: " << pt.x << std::endl;
    std::cout << "y: " << pt.y << std::endl;

    std::cout << "name: " << person.name << std::endl;
    std::cout << "age: " << person.age << std::endl;
}

With reflection, it is possible to write a generic print_members() that works for any struct - no manual edits are needed if you add, remove, or change fields.

#include <experimental/meta>
#include <iostream>
#include <string>

template <typename T>
void print_members(const T& obj) {
    constexpr auto ctx = std::meta::access_context::current();
    template for (constexpr auto member :
        std::define_static_array(nonstatic_data_members_of(^^T, ctx))) {
        std::cout << identifier_of(member) << ": " << obj.[:member:] << std::endl;
    }
}

struct Point { int x = 1; int y = 2; };
struct Person { std::string name = "Bob"; int age = 30; };

int main() {
    Point pt;
    Person person;

    print_members(pt);
    print_members(person);
}

The above code yields:

x: 1
y: 2
name: Bob
age: 30

Example 2: JSON Serialization of Structures

Below is a single-file example using Clang’s <experimental/meta> extension for C++26 reflection. The code provides a function to serialize any struct (with appropriate members) to a JSON string.

The function is then called on several different structures, including the two structure types (Point and Person) in the previous section and an additional User struct with two public and one private field

#include <experimental/meta>
#include <iostream>
#include <string>
#include <type_traits>

template <typename T>
std::string generate_json_str(const T& obj) {
    std::string json = "{";
    constexpr auto ctx = std::meta::access_context::current();
    bool first = true;

    template for (constexpr auto m :
        std::define_static_array(nonstatic_data_members_of(^^T, ctx))) {
        if (!first) json += ", ";
        first = false;
        json += "\"";
        json += identifier_of(m);
        json += "\": ";
        // Add quotes for string members
        if constexpr (std::is_same_v<decltype(obj.[:m:]), std::string>) {
            json += "\"";
            json += obj.[:m:];
            json += "\"";
        } else {
            json += std::to_string(obj.[:m:]);
        }
    }
    json += "}";
    return json;
}

struct Point { int x = 1; int y = 2; };
struct Person { std::string name = "Bob"; int age = 30; };

struct User {
    int id;
    std::string name;
private:
    double balance;
public:
    User(int i, std::string n, double b)
        : id(i), name(std::move(n)), balance(b) {}
};

int main() {
    Point point;
    Person person;
    User user{1, "Alice", 123.45};

    std::cout << "JSON of point: " << generate_json_str(point) << std::endl;
    std::cout << "JSON of person: " << generate_json_str(person) << std::endl;
    std::cout << "JSON of user: " << generate_json_str(user) << std::endl;
}

Outputs:

JSON of point: {"x": 1, "y": 2}
JSON of person: {"name": "Bob", "age": 30}
JSON of user: {"id": 1, "name": "Alice"}

Outro

This article has demonstrated only a small subset of the potential applications for C++26’s reflection facilities. The key takeaway is that compile-time reflection enables the creation of efficient and reusable code, with strong type safety enforced at compile time. Although some of the new syntax may appear complex at first glance, its use quickly becomes practical with familiarity.

As compiler and library support matures, compile-time reflection is likely to simplify and streamline many codebases and tooling workflows in the C++ ecosystem.

References

Ready to get started?

Contact IVC for a free consultation and discover how we can help your business grow online.

Contact IVC for a Free Consultation
Written by
Author Avatar
Engineering Core
ISB Vietnam's skilled software engineers deliver high-quality applications, leveraging their extensive experience in developing financial tools, business management systems, medical technology, and mobile/web platforms.

COMPANY PROFILE

Please check out our Company Profile.

Download

COMPANY PORTFOLIO

Explore my work!

Download

ASK ISB Vietnam ABOUT DEVELOPMENT

Let's talk about your project!

Contact US