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 namespaceAs 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.

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.