I wrote a small constexpr type/enum reflection library which I think may be a good addition to Boost. It needs C++17, although it relies on implementation-specific support (works on gcc, clang and msvc). https://github.com/zajo/reflecto
сб, 4 апр. 2026 г. в 21:48, Emil Dotchevski via Boost <boost@lists.boost.org>:
I wrote a small constexpr type/enum reflection library which I think may be a good addition to Boost. It needs C++17, although it relies on implementation-specific support (works on gcc, clang and msvc).
The type name reflection functionality already exists in Boost in TypeIndex library https://www.boost.org/doc/libs/1_91_0_beta1/doc/html/doxygen/boost_typeindex... : ``` static_assert( boost::typeindex::ctti_type_index:::type_id<int>().name() == std::string_view{"int"} ); ``` -- Best regards, Antony Polukhin
Hi Emil, If you expand this library (which I suppose is based upon the ideas in magic-enum), I would suggest adding the functionality in "light enum" available at https://github.com/gloinart/light_enum (note, made by me). Light enum has the same features as magic enum, with the difference that the enums are "registered" in .cpp files before usage. This way, the compile time overhead of magic enum is avoided. As a bonus, you can also introspect an enum even if you only have a forward declaration available. Best /Viktor On Sun, Apr 5, 2026 at 1:48 AM Emil Dotchevski via Boost < boost@lists.boost.org> wrote:
I wrote a small constexpr type/enum reflection library which I think may be a good addition to Boost. It needs C++17, although it relies on implementation-specific support (works on gcc, clang and msvc).
https://github.com/zajo/reflecto _______________________________________________ Boost mailing list -- boost@lists.boost.org To unsubscribe send an email to boost-leave@lists.boost.org https://lists.boost.org/mailman3/lists/boost.lists.boost.org/ Archived at: https://lists.boost.org/archives/list/boost@lists.boost.org/message/NLGU2ADV...
On Sun, Apr 5, 2026 at 10:36 AM Viktor Sehr via Boost <boost@lists.boost.org> wrote:
Hi Emil, If you expand this library (which I suppose is based upon the ideas in magic-enum), I would suggest adding the functionality in "light enum" available at https://github.com/gloinart/light_enum (note, made by me). Light enum has the same features as magic enum, with the difference that the enums are "registered" in .cpp files before usage. This way, the compile time overhead of magic enum is avoided.
Boost.Describe already does that and a ton more.
I don't know anything about the problem domain, except that "Reflecto" is the perfect name
I was thinking the opposite. I dislike "cute/clever" names.
Thanks _______________________________________________ Boost mailing list -- boost@lists.boost.org To unsubscribe send an email to boost-leave@lists.boost.org https://lists.boost.org/mailman3/lists/boost.lists.boost.org/ Archived at: https://lists.boost.org/archives/list/boost@lists.boost.org/message/FQR44BD7...
On 4 Apr 2026 21:47, Emil Dotchevski via Boost wrote:
I wrote a small constexpr type/enum reflection library which I think may be a good addition to Boost. It needs C++17, although it relies on implementation-specific support (works on gcc, clang and msvc).
Why are the enum_lookup_range limits necessary? As far as I could tell from my brief glance at the code, you simply cut the enum value names from function signature strings, no actual lookup is involved, so why the limits? Also, since the library only deals with producing name strings for types and enum values, I think Reflecto is a bit ambitious name. I would expect more advanced features from a reflection library, e.g. the ability to iterate over enum values or struct data members.
On Mon, Apr 6, 2026 at 6:42 AM Andrey Semashev via Boost < boost@lists.boost.org> wrote:
On 4 Apr 2026 21:47, Emil Dotchevski via Boost wrote:
I wrote a small constexpr type/enum reflection library which I think may be a good addition to Boost. It needs C++17, although it relies on implementation-specific support (works on gcc, clang and msvc).
Why are the enum_lookup_range limits necessary? As far as I could tell from my brief glance at the code, you simply cut the enum value names from function signature strings, no actual lookup is involved, so why the limits?
- enum_value_name() can be invoked with a variable at run-time. This is implemented in terms of indexing a constexpr array constructed over the lookup range at compile time. If the value is out of the lookup range, that's indicated in the state of the returned name object. - enum_value_names<E> returns a constexpr array of name/value pairs (like Describe does for described enums) that includes only the named values; there is also named_enum_value_count and min_/max_named_enum_value.
Am 06.04.26 um 17:07 schrieb Emil Dotchevski via Boost:
On Mon, Apr 6, 2026 at 6:42 AM Andrey Semashev via Boost < boost@lists.boost.org> wrote:
Why are the enum_lookup_range limits necessary? As far as I could tell from my brief glance at the code, you simply cut the enum value names from function signature strings, no actual lookup is involved, so why the limits?
- enum_value_name() can be invoked with a variable at run-time. This is implemented in terms of indexing a constexpr array constructed over the lookup range at compile time. If the value is out of the lookup range, that's indicated in the state of the returned name object.
- enum_value_names<E> returns a constexpr array of name/value pairs (like Describe does for described enums) that includes only the named values; there is also named_enum_value_count and min_/max_named_enum_value. That sounds like a heavy footgun: You can always get the name of an enumerator / all enumerators , except when you cannot. For name<->enumerator conversions you could throw/static_assert to detect this case. For try-to-name like functions you cannot. And lists of enumerator names will just be incomplete.
This is amplified by this being a define (BOOST_REFLECTO_DEFAULT_ENUM_MIN_VALUE): When someone (e.g. a consumer of your library built on reflecto) has already included reflecto and/or defined those then your code will suddenly break and/or have UB. At least you can specialize a trait for "your" enums, but it's in the boost::reflecto namespace so requires including that header first which is intrusive. Speaking of it: I'd suggest to allow specifying the first and last enumerators there, not (only) integers. Similar `static_cast<int>(EnumValue)` could be problematic.
On Tue, Apr 7, 2026 at 3:12 AM Alexander Grund via Boost < boost@lists.boost.org> wrote:
Am 06.04.26 um 17:07 schrieb Emil Dotchevski via Boost:
- enum_value_names<E> returns a constexpr array of name/value pairs (like Describe does for described enums) that includes only the named values; there is also named_enum_value_count and min_/max_named_enum_value. That sounds like a heavy footgun: You can always get the name of an enumerator / all enumerators , except when you cannot. For name<->enumerator conversions you could throw/static_assert to detect this case. For try-to-name like functions you cannot.
For runtime lookups, the returned name object can be checked to see if the lookup was successful. That's the best behavior possible (it is not undefined behavior).
This is amplified by this being a define (BOOST_REFLECTO_DEFAULT_ENUM_MIN_VALUE): When someone (e.g. a consumer of your library built on reflecto) has already included reflecto and/or defined those then your code will suddenly break
This is a very good point and it inspired me to find a solution. Now the enum_lookup_range can be specified for all enums within a given namespace, not just for individual enums: namespace lib1 { struct this_namespace; enum class some_enum { .... }; } namespace boost::reflecto { template <> struct enum_lookup_range<specialize_for_namespace<lib1::this_namespace>> { // specialization applies for any enum within the namespace lib1, // including lib1::some_enum. }; } I made this machinery part of the public API in meta_specialization.hpp, so the ability to look up a template specialization based on the namespace of some type is universally available, see https://github.com/zajo/reflecto?tab=readme-ov-file#meta-specialization.
Am 10.04.26 um 23:32 schrieb Emil Dotchevski via Boost:
On Tue, Apr 7, 2026 at 3:12 AM Alexander Grund via Boost < boost@lists.boost.org> wrote:
Am 06.04.26 um 17:07 schrieb Emil Dotchevski via Boost:
- enum_value_names<E> returns a constexpr array of name/value pairs (like Describe does for described enums) that includes only the named values; there is also named_enum_value_count and min_/max_named_enum_value. That sounds like a heavy footgun: You can always get the name of an enumerator / all enumerators , except when you cannot. For name<->enumerator conversions you could throw/static_assert to detect this case. For try-to-name like functions you cannot.
For runtime lookups, the returned name object can be checked to see if the lookup was successful. That's the best behavior possible (it is not undefined behavior). My point was: At runtime you cannot check if you really got all enumerators unless you know them or their range already. And hence you cannot convert a string to enumerator distinguishing an invalid name from one missed by the library.
This is amplified by this being a define (BOOST_REFLECTO_DEFAULT_ENUM_MIN_VALUE): When someone (e.g. a consumer of your library built on reflecto) has already included reflecto and/or defined those then your code will suddenly break
This is a very good point and it inspired me to find a solution. Now the enum_lookup_range can be specified for all enums within a given namespace, not just for individual enums:
namespace lib1 { struct this_namespace;
enum class some_enum { .... }; }
namespace boost::reflecto { template <> struct enum_lookup_range<specialize_for_namespace<lib1::this_namespace>> { // specialization applies for any enum within the namespace lib1, // including lib1::some_enum. }; }
I made this machinery part of the public API in meta_specialization.hpp, so the ability to look up a template specialization based on the namespace of some type is universally available, see https://github.com/zajo/reflecto?tab=readme-ov-file#meta-specialization. _______________________________________________
That's better, yes. Just for comparison: For a case where I needed the range of enumerators reliably I added customization points as opt-in: `constexpr Enum getLastEnumerator(Enum)` This was supposed to be implemented for an enum to opt-in with the contract that enum values from 0 to the returned one are valid. It can be put right after the enum definition where it is easy to verify and update, and doesn't require any includes. Your trait needs including a reflecto header and likely remembering to include the header where the trait is defined before using the reflecto machinery. Not sure how well this works on all compilers depending on the include order. I remember having had issues with Boost.Test to specialize the `boost_test_print`(?) trait to get my own types to be streamable. But there it was at least a compile error. To be clear: I'm NOT saying there is a better solution than yours, just want to make sure you and ultimately the users of reflecto are aware of such subtleties
On 6 Apr 2026 18:07, Emil Dotchevski via Boost wrote:
On Mon, Apr 6, 2026 at 6:42 AM Andrey Semashev via Boost < boost@lists.boost.org> wrote:
On 4 Apr 2026 21:47, Emil Dotchevski via Boost wrote:
I wrote a small constexpr type/enum reflection library which I think may be a good addition to Boost. It needs C++17, although it relies on implementation-specific support (works on gcc, clang and msvc).
Why are the enum_lookup_range limits necessary? As far as I could tell from my brief glance at the code, you simply cut the enum value names from function signature strings, no actual lookup is involved, so why the limits?
- enum_value_name() can be invoked with a variable at run-time. This is implemented in terms of indexing a constexpr array constructed over the lookup range at compile time. If the value is out of the lookup range, that's indicated in the state of the returned name object.
- enum_value_names<E> returns a constexpr array of name/value pairs (like Describe does for described enums) that includes only the named values; there is also named_enum_value_count and min_/max_named_enum_value.
I think, if the above functionality may silently fail, if my enum happen to have values outside the limits, I would rather prefer if I had to explicitly specify the limits or the individual enum name<->value pairs. Having a functionality that "just works" is only good when it means "always works", not when it "usually works". Maybe the library could be split in two layers. The lowest layer would only deal with compile-time conversions that don't require limits or individual name<->value pairs. The runtime layer would be built on top of that and would require the user to "register" his enums for that layer to work. Although, I guess, Boost.Describe already provides that runtime behavior, so maybe that layer is not really needed.
participants (7)
-
Alexander Grund -
Andrey Semashev -
Antony Polukhin -
Emil Dotchevski -
Robert Ramey -
Viktor Sehr -
Vinnie Falco