[#MRDOCS_ASSERT] = MRDOCS_ASSERT :mrdocs: Assert that a condition holds. == Synopsis Declared in `<mrdocs/Support/Error/Assert.hpp>` [source,cpp,subs="verbatim,replacements,macros,-callouts"] ---- #define MRDOCS_ASSERT(x) ---- == Description Use it as a statement, with a trailing semicolon, to check a precondition or invariant: [,cpp] ---- namespace mrdocs { int elementAt(std::vector const& v, std::size_t i) { MRDOCS_ASSERT(i < v.size()); return v[i]; } } // mrdocs ---- In debug builds, the assertion roughly expands to: [,cpp] ---- // MRDOCS_ASSERT(i < v.size()); // The condition is evaluated once. If it's false, // assert_failed prints "assertion failed: i < v.size() // on line N in " to stderr, and then the program // traps (__builtin_trap on GCC/Clang, __debugbreak on // MSVC). static_cast(!!(i < v.size()) || (assert_failed("i < v.size()", __builtin_FILE(), __builtin_LINE()), static_cast(__builtin_trap(), __builtin_unreachable()), true)); ---- In release builds (`NDEBUG`), it expands to: [,cpp] ---- // MRDOCS_ASSERT(i < v.size()); // The condition is dropped by the preprocessor. It's // never compiled or evaluated. static_cast(false); ---- Some consequences of this definition: * The condition must not have side effects the program depends on, such as `MRDOCS_ASSERT(queue.pop())`, since release builds never run it. Variables used only inside assertions can trigger unused‐variable warnings there. * The expansion calls `assert_failed` unqualified, so in debug builds the macro only compiles where `mrdocs::assert_failed` is found by lookup: inside `namespace mrdocs`, or after `using namespace mrdocs;`. * It's a `void` expression, not a full statement, so a trailing semicolon is needed. * It's a single‐argument macro. Wrap a condition that has a top‐level comma in parentheses, as in `MRDOCS_ASSERT((std::is_same_v[))]`. When to use it: * Preconditions of a function, such as a non‐null pointer from Clang (`MRDOCS_ASSERT(D)`) or an index in range. * Invariants of a type, such as `has_value()` in an accessor, `!valueless_after_move()` on a `Polymorphic`, or `t‐>Kind == T::kind_id` before a cast to the derived type. * Assumptions a later line depends on, such as a container being non‐empty before `front()`. Use it when there's a condition you can state, so a debug build prints it when it fails. When there's no condition and the location itself is the bug, such as the `default:` of a `switch` that handles every enumerator, use xref:MRDOCS_UNREACHABLE.adoc[`MRDOCS_UNREACHABLE`] instead. Neither macro is for input a user can control, since release builds don't check it: return an error with `MRDOCS_CHECK` or `MRDOCS_CHECK_OR` there. == Parameters [cols="1,4"] |=== | Name| Description | *x* | The condition to check. |=== == See Also xref:MRDOCS_UNREACHABLE.adoc[`MRDOCS_UNREACHABLE`] [.small]#Created with https://www.mrdocs.com[MrDocs]#