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.

Popular Articles

Fintech Development Outsourcing: The Ultimate Guide for 2026
OUTSOURCING

Fintech Development Outsourcing: The Ultimate Guide for 2026

November 25, 2025 · By ISB Vietnam(IVC) Business Development Team

Healthcare IT Outsourcing: A Complete Guide for Medical Software Development
OUTSOURCING

Healthcare IT Outsourcing: A Complete Guide for Medical Software Development

December 29, 2025 · By ISB Vietnam(IVC) Business Development Team

DevOps Best Practices: What to Build and What to Outsource
OUTSOURCING

DevOps Best Practices: What to Build and What to Outsource

March 16, 2026 · By ISB Vietnam(IVC) Business Development Team

What Is Adaptive Software Development (ASD)? A Practical Guide for Modern Engineering Teams
OUTSOURCING

What Is Adaptive Software Development (ASD)? A Practical Guide for Modern Engineering Teams

June 4, 2026 · By ISB Vietnam(IVC) Business Development Team

White Paper

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