r/cpp 14d ago

Toggleable Annotations for C++26 Reflection

https://github.com/RyanJK5/rjk-flag

Hey all, I put together a very simple reflection utility that lets you make toggleable annotations, similarly to explicit(bool) or noexcept(bool).

Try it on Compiler Explorer!

inline constexpr rjk::flag serializable{};
inline constexpr rjk::flag skip_field{};

template <typename T>
struct [[ =serializable ]] MyType {
    int x;
    int y;

    [[ =skip_field(std::is_pointer_v<T>) ]]
    T data;
};

// serializable is applied unconditionally
static_assert(rjk::is_flag_set(^^MyType<int>, serializable));

// skip_field is applied conditionally
static_assert(not rjk::is_flag_set(^^MyType<int>::data, skip_field));
static_assert(rjk::is_flag_set(^^MyType<int*>::data, skip_field));
26 Upvotes

6 comments sorted by

7

u/fortsnek274 14d ago

Why not [[=std::conditional_t<std::is_pointer_v<T>, Skip_field, std::monostate>{}]]?

11

u/Ok_Statistician_781 14d ago

You could do that, but the point is to reduce the verbosity a little bit. I should update the README motivation section to match your comment though.

6

u/jazzwave06 13d ago

This is so ugly lol

4

u/fortsnek274 13d ago

It's... beautiful!

Could do with language level support though. Whatever that would look like. Or stick a utility function in the std lib that will still end up with dummy attributes.

3

u/zerhud 14d ago

It seems auto& […p] = foo; can to be used . Next we can skip pointers inside serialize method with if constexpr. What is benefits from attributes?

4

u/Ok_Statistician_781 14d ago edited 14d ago

The reason I made this was a use-case from my other reflection library, duck: https://github.com/RyanJK5/rjk-duck. It lets you define a type-erased interface as a struct. There's an [[ =direct ]] annotation that indicates an interface member should be inlined directly in the duck instead of being stored in a vtable.

So for this interface:

struct Interface {
    int foo();

    [[ =rjk::direct ]]
    int bar();
};

rjk::duck<Interface> d{...};

duck looks like:

class duck<Interface> {
  private:
    void* m_data;
    vtable* m_vtable;
    int (*m_bar)(void* context);
};