What the heck is Reflection?

What the heck is Reflection?

With C++26, reflection has been introduced into our lives. Although it isn't fully supported by mainline compilers yet, we'll start hearing about it — and using it — soon.

Almost all of us, at some point, have written code to turn enums into strings so we can log them. The usual options? A giant switch-case, or some kind of lookup table. Both work, but both are fragile. Every time you add a new enumerator, you also have to remember to update the stringification logic. Forget once? We've all been there, hunting down an <unknown> bug at 2AM. Reflection gives us a much cleaner way out. So how does it actually work? It takes the stage with two new operators that open the door to a whole new world: ^^ and [: :].

Who are our new friends...

Let me introduce you to the new operator ^^, also known as the reflection operator. It's a unary operator that helps us break the fourth wall of the abstract machine. Put ^^ in front of pretty much any C++ entity – a type, a variable, a function, a namespace, a template – and you get back a std::meta::info value – a compile-time handle to that entity.

I can hear you saying "Errm... enough text, give me some code". Okay, okay..

int x;
constexpr std::meta::info r1 = ^^int;         // a type
constexpr std::meta::info r2 = ^^x;           // a variable
constexpr std::meta::info r3 = ^^std::vector; // a class template

namespace mylib {}
constexpr std::meta::info r4 = ^^mylib;       // a namespace

As you noticed, ^^, the reflection operator, doesn't care what you put in front of it – any C++ entity works. It always gives you back a std::meta::info constant expression.

What about our other mate? It is called the splicer[: :]. It helps us return to the abstract machine's reality. More precisely, it converts a std::meta::info value back into a usable C++ entity – a type, an expression, a template, depending on the context.

constexpr auto r1       = ^^int;
typename[:r1:] x        = 5;    // int x = 5;
typename[:^^double:] y  = 20.2; // double y = 20.2;

As you can see [: :], the splicer, takes a std::meta::info and converts it into a C++ entity.

You might be wondering right now why there's a typename keyword. It's a valid question but it's a topic for another day. Spoiler Alert! When we're not in a type-only context, we need to give the compiler a hint about what kind of entity we're splicing.

Let's make something handy!

At the beginning, I mentioned we can get rid of messy hand-written enum stringification. Now, it's time to show you:

#include <meta>
#include <iostream>
#include <type_traits>
#include <string_view>

template<typename T>
requires std::is_enum_v<T>
constexpr std::string_view to_enum_string(T val)
{
    template for (constexpr auto e :  
                  std::define_static_array(std::meta::enumerators_of(^^T))) {
        if (val == [:e:])
            return std::meta::identifier_of(e);
    }
    return "<unknown>";
}

enum class Colors
{
    Red,
    Yellow,
    Green
};

int main() {
    std::cout << to_enum_string(Colors::Red) << "\n";
    std::cout << to_enum_string(Colors::Yellow) << "\n";
    std::cout << to_enum_string(Colors::Green) << "\n";
}

The code might look a bit scary at first but it saves us from writing dirty and error-prone stringification implementation. Also, you might be curious about what's define_static_array? It comes with another C++26 proposal. We'll talk about it later...

If you wanna try it yourself, here it is.

Compiler Explorer - C++ (x86-64 gcc 16.1)
template<typename T> requires std::is_enum_v<T> constexpr std::string_view to_enum_string(T val) { template for (constexpr auto e : std::define_static_array(std::meta::enumerators_of(^^T))) { if (val == [:e:]) return std::meta::identifier_of(e); } return ”<unknown>”; } enum class Colors { Red, Yellow, Green }; int main() { std::cout << to_enum_string(Colors::Red) << ”\n”; std::cout << to_enum_string(Colors::Yellow) << ”\n”; std::cout << to_enum_string(Colors::Green) << ”\n”; }

That's all about our new mates – ^^ and [: :] . Personally, I'm so eager to use them in production to see what I can do.

As a next step, we need to talk about std::meta::info...


Disclaimer

This post was written by a human, with AI assistance for language polishing.


References

[P2996R13] Reflection for C++26

Subscribe to Murat Hepeyiler

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe