MRDOCS_DESCRIBE_KINDS_BEGIN

Open a kinds description driven by an X‐macro .inc file.

Synopsis

#define MRDOCS_DESCRIBE_KINDS_BEGIN©

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:

#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:

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:

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):

// MRDOCS_DESCRIBE_KINDS_BEGIN(Shape): leaves the call open
static_assert(std::is_class_v<Shape>, "...");
[[maybe_unused]]
inline decltype(kind_descriptor_fn_impl(0

// #include "ShapeNodes.inc": one MRDOCS_KIND_ENTRY per INFO line
    , kind_descriptor<Shape, CircleShape>{}   // INFO(Circle)
    , kind_descriptor<Shape, SquareShape>{}   // 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

Name

Description

C

The polymorphic base class.

Created with MrDocs