2.3. Reflection: Notes - TheNitesWhoSay/RareCpp GitHub Wiki

As described in REFLECT Macro, NOTEs are a way of attaching additional information (which is known at compile time) to various reflected objects/members.

In vanilla RareCpp there are four kinds of elements to which notes can be attached.

  1. Reflected classes ("Class-level annotations")
  2. Reflected class members
  3. Super-class relationships
  4. Overload descriptions

Because notes for super-class relationships are contained within the NOTE for reflected classes, and because notes for particular overloads are contained within the NOTE for reflected class members, these are sometimes referred to as "sub-notes".

All notes share a common interface consisting of:

  • Notes - type of the notes on this element
  • notes - reference to the tuple containing the values of the notes for this element
  • hasNote<T>() - returns a bool indicating whether the notes for this element contain a note of type "T"
  • hasNote<Of>() - returns a bool indicating whether the notes for this element contain a note specializing template "Of"
  • getNote<T>() - returns a reference to the first instance of type "T" in the notes for this element
  • getNote<Of>() - returns a reference to the first instance of type specializing template "Of" in the notes for this element
  • forEachNote(func) - calls func for every note on this element
  • forEachNote<T>(func) - calls func for every note of type "T" on this element
  • forEachNote<Of>(func) - calls func for every note specializing template "Of" on this element

This common interface is accessed a little differently for the different element types...

1.) Reflected classes - RareTs::Notes<T>::

2.) Reflected class members - RareTs::Member<T, I>:: or RareTs::MemberType<T>::

  • RareTs::Member is the same as the type of the member that is passed to Reflect<T>::Member::forEach and similar methods, and can be accessed through that
  • See example

3.) Super-class relationships - RareTs::Supers<T>::SuperInfo<I>::

  • RareTs::Supers<T>::SuperInfo is the same as the type of "superInfo" that is passed to Reflect<T>::Supers::forEach and similar methods, and can be accessed through that
  • See example

4.) Overloads - RareTs::Member<T, I>::Overloads::Overload<I>::

  • RareTs::Member<T, I>::Overloads::Overload is the same as the type of "overloadInfo that is passed to Reflect<T>::Member<I>::Overloads::forEach and similar methods, and can be accessed through that
  • See example

User-defined notes

Notes are values available at compile-time, so not everything can be a NOTE, for instance std::string cannot be used at compile time; but many things can (e.g. const char*, std::string_view, primitive integers, and user-defined structures).

Creating your own note can be as simple as creating your own type e.g.

struct Alias
{
	std::string_view value;
};

// Alias can now be used in notes e.g.
NOTE(someElement, Alias{"NewElementName"})

Conventionally, the value placed in NOTE shouldn't require "()" or "{}" if it has no values, so when creating such a note, you create both a type and an instance of that type:

struct IgnoreType {};
inline constexpr IgnoreType Ignore{};

template <size_t Value> IdType { static constexpr size_t value = Value };
template <size_t Value> inline constexpr IdType<Value> Id;

// Ignore and Id can now be used as annotations e.g.
NOTE(someElement, Id<1234>, Ignore)

This helps reduce noise, especially in more advanced patterns such as having an annotation overload operator() to return some compound type as is the case for RareTs::Super and RareTs::Overload.

See also:

⚠️ **GitHub.com Fallback** ⚠️