[#MRDOCS_DESCRIBE_KINDS_BEGIN] = MRDOCS_DESCRIBE_KINDS_BEGIN :mrdocs: Open a kinds description driven by an X‐macro `.inc` file. == Synopsis Declared in `<mrdocs/Support/Reflection/Describe.hpp>` [source,cpp,subs="verbatim,replacements,macros,-callouts"] ---- #define MRDOCS_DESCRIBE_KINDS_BEGIN(C) ---- == Description When the derived kinds already live in an X‐macro `.inc` file (one `INFO(Name)` per kind, often the same file that builds the kind enum), this registers them without repeating the list in `MRDOCS_DESCRIBE_KINDS`. Point `INFO` at `MRDOCS_KIND_ENTRY`, then bracket the include with this macro and `MRDOCS_DESCRIBE_KINDS_END`. Given this `ShapeNodes.inc`: [,cpp] ---- #ifndef INFO #define INFO(Name) #endif INFO(Circle) INFO(Square) #undef INFO ---- a header can build both the enum and the kind list from it: [,cpp] ---- namespace shapes { enum class ShapeKind { #define INFO(Name) Name, #include "ShapeNodes.inc" }; struct Shape { ShapeKind Kind; }; struct CircleShape : Shape { static constexpr ShapeKind kind_id = ShapeKind::Circle; CircleShape() : Shape{kind_id} {} }; struct SquareShape : Shape { static constexpr ShapeKind kind_id = ShapeKind::Square; SquareShape() : Shape{kind_id} {} }; #define INFO(Name) MRDOCS_KIND_ENTRY(Shape, Name##Shape) MRDOCS_DESCRIBE_KINDS_BEGIN(Shape) #include "ShapeNodes.inc" MRDOCS_DESCRIBE_KINDS_END(Shape) } // namespace shapes ---- The entries can also be written by hand, and an empty pair registers a base with no kinds: [,cpp] ---- MRDOCS_DESCRIBE_KINDS_BEGIN(Node) MRDOCS_KIND_ENTRY(Node, Leaf) MRDOCS_KIND_ENTRY(Node, Branch) MRDOCS_DESCRIBE_KINDS_END(Node) MRDOCS_DESCRIBE_KINDS_BEGIN(Empty) MRDOCS_DESCRIBE_KINDS_END(Empty) ---- After preprocessing, the `Shape` block becomes the following (simplified: the `::mrdocs::describe::detail::` qualification is dropped and the assertion message is shortened): [,cpp] ---- // MRDOCS_DESCRIBE_KINDS_BEGIN(Shape): leaves the call open static_assert(std::is_class_v, "..."); [[maybe_unused]] inline decltype(kind_descriptor_fn_impl(0 // #include "ShapeNodes.inc": one MRDOCS_KIND_ENTRY per INFO line , kind_descriptor{} // INFO(Circle) , kind_descriptor{} // INFO(Square) // MRDOCS_DESCRIBE_KINDS_END(Shape): closes the call )) mrdocs_kind_descriptor_fn(Shape**) { return {}; } ---- That's the same declaration `MRDOCS_DESCRIBE_KINDS(Shape, CircleShape, SquareShape)` produces, so the same queries (`describe::describe_kinds`, `describe::has_describe_kinds`, `mrdocs::visit`) work afterwards. Things to keep in mind: * This macro leaves a call open, so only `MRDOCS_KIND_ENTRY` expansions and preprocessor directives may come before the matching `MRDOCS_DESCRIBE_KINDS_END`. Anything else, including a stray `;`, is a syntax error. * Pass the same base to this macro, to every entry, and to `MRDOCS_DESCRIBE_KINDS_END`. * Place the block at namespace scope, in the namespace of the base. * Define `INFO` before the include. The `.inc` file is expected to `#undef` it at the end; if yours doesn't, add the `#undef` yourself. == Parameters [cols="1,4"] |=== | Name| Description | *C* | The polymorphic base class. |=== [.small]#Created with https://www.mrdocs.com[MrDocs]#