Extraction

The filters are the gate at the front of the pipeline. They decide which symbols enter the corpus. The options on this page are the next stage: they decide how MrDocs interprets and arranges the symbols that survived the filters. Which inherited members appear on a class page, the order members are listed in, how related declarations are grouped (overload sets, SFINAE expressions, function objects), what MrDocs infers from doc comments (briefs, relations, function metadata), and the escape hatches for headers the compiler cannot find. The Extraction reference lists every option.

Ordering members

By default, members appear alphabetically within each kind. The sort-members family overrides that order when you want a more conventional grouping (constructors first, destructors first, conversions and relational operators last, and so on).

Example
/// A class declared with members in deliberately
/// scattered order to show how sorting affects the
/// rendered member list.
struct gadget
{
    /// Refresh the gadget.
    void refresh();
    /// Construct a gadget.
    gadget();
    /// Hide the gadget.
    void hide();
    /// Show the gadget.
    void show();
    /// Destroy the gadget.
    ~gadget();
};
mrdocs.yml
sort-members: true
Preview
gadget

A class declared with members in deliberately scattered order to show how sorting affects the rendered member list.

Synopsis

Declared in <sort‐members.cpp>

struct gadget;
Member Functions

Name

Description

gadget [constructor]

Construct a gadget.

~gadget [destructor]

Destroy the gadget.

hide

Hide the gadget.

refresh

Refresh the gadget.

show

Show the gadget.

gadget::gadget

Construct a gadget.

Synopsis

Declared in <sort‐members.cpp>

gadget();
gadget::~gadget

Destroy the gadget.

Synopsis

Declared in <sort‐members.cpp>

~gadget();
gadget::hide

Hide the gadget.

Synopsis

Declared in <sort‐members.cpp>

void
hide();
gadget::refresh

Refresh the gadget.

Synopsis

Declared in <sort‐members.cpp>

void
refresh();
gadget::show

Show the gadget.

Synopsis

Declared in <sort‐members.cpp>

void
show();

The other sort switches (sort-members-ctors-1st, sort-members-dtors-1st, sort-members-assignment-1st, sort-members-conversion-last, sort-members-relational-last) refine which member kinds float to the top or sink to the bottom. sort-members-by and sort-namespace-members-by pick between alphabetical and declaration order.

Overload sets

A C++ overload set is many functions sharing a name. overloads merges them into a single page so the reader sees the whole set at once instead of one page per signature:

Example
/** Compute the absolute value of an integer.

    One overload takes `int` and the other `long`,
    so the documentation page lists both side by side.
*/
int abs(int x);

/// @copydoc abs(int)
long abs(long x);
mrdocs.yml
overloads: true
Preview
abs

Compute the absolute value of an integer.

Synopses

Declared in <overloads.cpp>

Compute the absolute value of an integer.

int
abs(int x);

Compute the absolute value of an integer.

long
abs(long x);
abs

Compute the absolute value of an integer.

Synopsis

Declared in <overloads.cpp>

int
abs(int x);
Description

One overload takes int and the other long, so the documentation page lists both side by side.

abs

Compute the absolute value of an integer.

Synopsis

Declared in <overloads.cpp>

long
abs(long x);
Description

One overload takes int and the other long, so the documentation page lists both side by side.

SFINAE constraints

sfinae rewrites SFINAE constraints into a readable form instead of the raw enable_if machinery:

Example
#include <type_traits>

/** Multiply by two, but only for integers.

    The `std::enable_if_t` SFINAE on the return type
    restricts the overload to integral arguments.
*/
template <class T>
std::enable_if_t<std::is_integral_v<T>, T>
twice(T x);
mrdocs.yml
sfinae: true
Preview
twice

Multiply by two, but only for integers.

Synopsis

Declared in <sfinae.cpp>

template<class T>
T
twice(T x)
requires std::is_integral_v<T>;
Description

The std::enable_if_t SFINAE on the return type restricts the overload to integral arguments.

Algorithm function objects

auto-function-objects detects the Algorithm Function Object (AFO) idiom and presents the variable’s page as if it were a function, using the call operator’s doc comment, parameters, and return type:

include/numerics/clamp.hpp
namespace numerics {

struct clamp_fn
{
    /** Constrain a value to the inclusive range `[lo, hi]`.

        Returns `lo` when `v < lo`, `hi` when `hi < v`, otherwise `v`.
        Behavior is undefined if `hi < lo`.

        @tparam T  A type comparable with `operator<`.
        @param  v  The value to constrain.
        @param  lo The inclusive lower bound.
        @param  hi The inclusive upper bound.
        @return A copy of `v`, `lo`, or `hi`, whichever lies within the range.
    */
    template <class T>
    T operator()(T const& v, T const& lo, T const& hi) const;
};

inline constexpr clamp_fn clamp = {};

}
mrdocs.yml
auto-function-objects: true
Preview
numerics::clamp

Constrain a value to the inclusive range [lo, hi].

Synopsis

Declared in <numerics/clamp.hpp>

template<class T>
T
clamp(
    T const& v,
    T const& lo,
    T const& hi);

This function is defined as an Algorithm Function Object (AFO).

Description

Returns lo when v < lo, hi when hi < v, otherwise v. Behavior is undefined if hi < lo.

Return Value

A copy of v, lo, or hi, whichever lies within the range.

Template Parameters

Name

Description

T

A type comparable with operator<.

Parameters

Name

Description

v

The value to constrain.

lo

The inclusive lower bound.

hi

The inclusive upper bound.

When auto-detection misses an AFO (the call-operator type has extra members, or the variable is not the only AFO-shaped constant in its scope), tag the variable with the @functionobject doc-comment command. Same effect, declared next to the symbol rather than left to inference.

Inferred metadata

MrDocs fills several kinds of metadata from the signature when the doc comment leaves them out. Each kind is governed by its own switch.

Briefs

By default, the first sentence of a doc comment becomes the brief and the rest becomes the detailed description. auto-brief is on by default; turn it off if you want every brief written explicitly with @brief.

Example
/** Truncate a string to the given length.

    The first sentence of this comment becomes the
    brief; the rest is the description.
*/
void truncate(char* s, int n);
mrdocs.yml
auto-brief: true
Preview
truncate

Truncate a string to the given length.

Synopsis

Declared in <auto‐brief.cpp>

void
truncate(
    char* s,
    int n);
Description

The first sentence of this comment becomes the brief; the rest is the description.

Non-member functions

The "non-member functions" section on a class page is very useful to gather free functions that operate on the class, but it is a pain to maintain by hand. auto-relates is on by default to do the work for you. It looks for free functions that take the class as a parameter or return it and lists them under the class’s "Non-Member Functions" section, without needing any explicit tagging in the doc comment.

Example
/** A two-dimensional point.
*/
struct point
{
    double x;
    double y;
};

/** Print a point to stdout.

    The free function takes `point` as its only
    parameter, so it gets attached to `point` as a
    related function.
*/
void print(point p);
mrdocs.yml
auto-relates: true
Preview
point

A two‐dimensional point.

Synopsis

Declared in <auto‐relates.cpp>

struct point;
Data Members

Name

x

y

Non-Member Functions

Name

Description

print

Print a point to stdout.

point::x
Synopsis

Declared in <auto‐relates.cpp>

double x;
point::y
Synopsis

Declared in <auto‐relates.cpp>

double y;
print

Print a point to stdout.

Synopsis

Declared in <auto‐relates.cpp>

void
print(point p);
Description

The free function takes point as its only parameter, so it gets attached to point as a related function.

Parameters

Name

Description

p

A two‐dimensional point.

Function metadata

auto-function-metadata (on by default) fills in function documentation that authors typically omit because the result is mechanical or repetitive: the brief of a copy constructor, the parameter doc on operator==, the return value of a conversion operator. MrDocs writes the boilerplate so the hand-written comments can focus on what is actually unique to each function.

Example
/// A 2D vector.
struct vec2
{
    /// Construct from `x` and `y` components.
    vec2(double x, double y);

    vec2(vec2 const&);
    vec2(vec2&&) noexcept;
    ~vec2();

    vec2& operator=(vec2 const&);

    bool operator==(vec2 const&) const;

    /// Returns the Euclidean length of the vector.
    double magnitude() const;

    /// Translate this vector by `delta`.
    vec2 translated(vec2 const& delta) const;
};
mrdocs.yml
auto-function-metadata: true
Preview
vec2

A 2D vector.

Synopsis

Declared in <auto‐function‐metadata.cpp>

struct vec2;
Member Functions

Name

Description

vec2 [constructor]

Construct from x and y components.

~vec2 [destructor]

Destructor

operator=

Copy assignment operator

magnitude

Returns the Euclidean length of the vector.

translated

Translate this vector by delta.

operator==

Equality operator

vec2::vec2

Construct from x and y components.

Synopses

Declared in <auto‐function‐metadata.cpp>

Copy constructor

vec2(vec2 const& other);

Move constructor

vec2(vec2&& other) noexcept;

Construct from x and y components.

vec2(
    double x,
    double y);
vec2::vec2

Copy constructor

Synopsis

Declared in <auto‐function‐metadata.cpp>

vec2(vec2 const& other);
Parameters

Name

Description

other

The object to copy construct from

vec2::vec2

Move constructor

Synopsis

Declared in <auto‐function‐metadata.cpp>

vec2(vec2&& other) noexcept;
Parameters

Name

Description

other

The object to move construct from

vec2::vec2

Construct from x and y components.

Synopsis

Declared in <auto‐function‐metadata.cpp>

vec2(
    double x,
    double y);
Parameters

Name

Description

x

The value to construct from

vec2::~vec2

Destructor

Synopsis

Declared in <auto‐function‐metadata.cpp>

~vec2();
vec2::operator=

Copy assignment operator

Synopsis

Declared in <auto‐function‐metadata.cpp>

vec2&
operator=(vec2 const& other);
Return Value

Reference to the current object

Parameters

Name

Description

other

The object to copy assign from

vec2::magnitude

Returns the Euclidean length of the vector.

Synopsis

Declared in <auto‐function‐metadata.cpp>

double
magnitude() const;
Return Value

the Euclidean length of the vector.

vec2::translated

Translate this vector by delta.

Synopsis

Declared in <auto‐function‐metadata.cpp>

vec2
translated(vec2 const& delta) const;
Return Value

A 2D vector.

Parameters

Name

Description

delta

A 2D vector.

vec2::operator==

Equality operator

Synopsis

Declared in <auto‐function‐metadata.cpp>

bool
operator==(vec2 const& rhs) const;
Return Value

true if the objects are equal, false otherwise

Parameters

Name

Description

rhs

The right operand

Several inferences in one example:

  • The copy and move constructors, the destructor, the copy assignment operator, and operator== get full briefs ("Copy constructor", "Destructor", and so on) even though the source did not write one.

  • None of those declarations name their parameter either, but MrDocs picks names from the function’s role: other for the single-parameter constructors and operator=, rhs for the binary operator==.

  • The parameter docs are filled the same way ("The object to copy construct from", "The right operand"). operator= and operator== get return-value entries derived from their conventional contract ("Reference to the current object", "`true` if the objects are equal, false otherwise").

  • vec2::magnitude has only a brief in the source, but the brief begins with "Returns", so MrDocs lifts the rest of the sentence into the @return entry.

  • And vec2::translated, an ordinary member function with only a brief, picks up vec2’s own brief ("A 2D vector.") for both its `delta parameter and its return value, because no role-based rule applies and the type itself is documented.

Inherited members

When a class inherits from another, inherit-base-members determines how the inherited members should appear in the documentation.

never: The strictest setting lists the base relationship but does not repeat the base’s members on the derived page. This is the style used by cppreference. Readers follow the link to the base to see what they inherited:

Example
/// A drawable shape.
struct shape
{
    /// Render the shape.
    void draw();
};

/// A circle.
struct circle : shape
{
    /// Construct a circle of the given radius.
    explicit circle(double r);
};
mrdocs.yml
inherit-base-members: never
Preview
circle

A circle.

Synopsis

Declared in <inherited‐members‐never.cpp>

struct circle
    : shape
Base Classes

Name

Description

shape

A drawable shape.

Member Functions

Name

Description

circle [constructor]

Construct a circle of the given radius.

circle::circle

Construct a circle of the given radius.

Synopsis

Declared in <inherited‐members‐never.cpp>

explicit
circle(double r);
Parameters

Name

Description

r

The value to construct from

shape

A drawable shape.

Synopsis

Declared in <inherited‐members‐never.cpp>

struct shape;
Member Functions

Name

Description

draw

Render the shape.

Derived Classes

Name

Description

circle

A circle.

shape::draw

Render the shape.

Synopsis

Declared in <inherited‐members‐never.cpp>

void
draw();

circle's page lists only its own constructor. The inherited draw is reachable through the link to shape. This is the model cppreference uses for the standard library. Technically correct, but most library docs do not want it: a reader landing on circle has to chase a link to find out what they can call on it.

reference: lists the inherited members directly on the derived class’s page. Each entry links back to the member of the base class, so the base class is the source of truth:

mrdocs.yml
inherit-base-members: reference
Preview
figure

A drawable figure.

Synopsis

Declared in <inherited‐members‐reference.cpp>

struct figure;
Member Functions

Name

Description

draw

Render the figure.

Derived Classes

Name

Description

square

A square.

figure::draw

Render the figure.

Synopsis

Declared in <inherited‐members‐reference.cpp>

void
draw();
square

A square.

Synopsis

Declared in <inherited‐members‐reference.cpp>

struct square
    : figure
Base Classes

Name

Description

figure

A drawable figure.

Member Functions

Name

Description

square [constructor]

Construct a square of the given side.

draw

Render the figure.

square::square

Construct a square of the given side.

Synopsis

Declared in <inherited‐members‐reference.cpp>

explicit
square(double side);
Parameters

Name

Description

side

The value to construct from

draw is now visible in circle's Member Functions table, alongside the constructor. Its link points at shape::draw, so there is no duplicate page. This is the natural choice when every base class lives in the corpus and has its own page.

copy-dependencies (the default) is meant to handle specializations more gracefully. The motivation for this option is that two patterns break the reference model:

  • Implicit template specializations. class version: public detail::comparable<version> references detail::comparable<version>, which the user did not write explicitly. MrDocs cannot point to a "see the base" link on a page that does not exist and creating a reference to the primary template detail::comparable<T> is not helpful because the reader cannot see the inherited members without following the link and mentally substituting version for T.

  • Bases that are not in the corpus at all (a private detail header, an excluded vendor class, a system header). There is nowhere for the link to go.

In both cases, the reference option would leave the inherited members invisible or create a reference to a primary template that’s semantically hard to interpret. The default, copy-dependencies, behaves like reference when the base is already in the corpus. However, it uses the C++ compiler to actually instantiate the members for other cases, and copies the members of the instantiated base class into the derived page when the base is a dependency, so they are documented in place with the concrete operand types substituted in:

Example
namespace detail {

/// CRTP base that lifts `compare()` into `operator==` and `operator!=`.
template <class T>
struct comparable
{
    /// True if `compare()` is `0`.
    bool operator==(T const& other) const noexcept;
    /// True otherwise.
    bool operator!=(T const& other) const noexcept;
};

}

/// A semantic version `(major, minor)`.
struct version : detail::comparable<version>
{
    /// Construct from major and minor numbers.
    version(int major, int minor) noexcept;

    /// Three-way comparison against another version.
    int compare(version const& other) const noexcept;

    /// The major component.
    int major;
    /// The minor component.
    int minor;
};
mrdocs.yml
inherit-base-members: copy-dependencies
implementation-defined:
  - 'detail::**'
Preview
version

A semantic version (major, minor).

Synopsis

Declared in <inherited‐members‐specialization.cpp>

struct version
    : /* implementation-defined */
Base Classes

Name

Description

/* implementation-defined */

CRTP base that lifts compare() into operator== and operator!=.

Member Functions

Name

Description

version [constructor]

Construct from major and minor numbers.

compare

Three‐way comparison against another version.

operator==

Equality operator

operator!=

Inequality operator

Data Members

Name

Description

major

The major component.

minor

The minor component.

version::version

Construct from major and minor numbers.

Synopsis

Declared in <inherited‐members‐specialization.cpp>

version(
    int major,
    int minor) noexcept;
Parameters

Name

Description

major

The value to construct from

version::compare

Three‐way comparison against another version.

Synopsis

Declared in <inherited‐members‐specialization.cpp>

int
compare(version const& other) const noexcept;
Parameters

Name

Description

other

A semantic version (major, minor).

version::operator==

Equality operator

Synopsis

Declared in <inherited‐members‐specialization.cpp>

bool
operator==(version const& other) const noexcept;
Return Value

true if the objects are equal, false otherwise

Parameters

Name

Description

other

The right operand

version::operator!=

Inequality operator

Synopsis

Declared in <inherited‐members‐specialization.cpp>

bool
operator!=(version const& other) const noexcept;
Return Value

true if the objects are not equal, false otherwise

Parameters

Name

Description

other

The right operand

version::major

The major component.

Synopsis

Declared in <inherited‐members‐specialization.cpp>

int major;
version::minor

The minor component.

Synopsis

Declared in <inherited‐members‐specialization.cpp>

int minor;

The configuration marks the detail namespace as implementation-defined, so neither the primary template detail::comparable nor any of its symbols have a page of their own and every reference to one of them renders as /* implementation-defined */. version's base class in the rendered synopsis is exactly that placeholder. The specialization detail::comparable<version> is therefore a pure dependency. copy-dependencies reaches into that instantiated base and copies its members onto version's page: operator== and operator!= appear in version's Member Functions table, with the parameter type rewritten to version const& and the boilerplate brief, parameter doc, and return value supplied by auto-function-metadata. The reader gets the full API of version in one place, with nothing referring outwardly to a base that has no page.

This is one of the larger gaps between MrDocs and other tools. Other tools could at most document the primary comparable<T> and report the inheritance, but the implicit specialization comparable<version> is not an entity that can be introspected without a compiler. The inherited operators silently disappear from version's page, and the Boost.Operators / CRTP idiom becomes invisible in the rendered docs. MrDocs treats the specialization as a first-class dependency and copies the resolved members into the derived class.

copy-all: The last possible setting copies every base member into every derived page, regardless of whether the base is in the corpus. It flattens the documentation: a reader on a derived page sees the full surface inline, with no need to follow base-class links. The price is duplication: the same member is documented on every class that inherits it.

Missing headers

The platform for a documentation build often doesn’t have the same dependencies and system libraries available. If a header is genuinely unavailable, the Migration Notes walk through the practical solutions. One of them is defining shims for these dependencies. The other options can be specified in the configuration file.

missing-include-shims lets you describe stub contents for individual headers directly in the configuration file (the key is the include path, the value is the file body MrDocs presents to the compiler):

missing-include-shims:
  fmt/format.h: |
    namespace fmt { template <class...> struct format_string {}; }

missing-include-prefixes tells MrDocs which include paths to forgive when they cannot be found, so the surrounding code parses anyway:

missing-include-prefixes:
  - external/

Reach for these only when you need to. They are the answer to "MrDocs can’t find this header and I cannot install it"; if you can adjust the compilation database, that is the better path.