Assert that a condition holds.
Declared in <mrdocs/Support/Error/Assert.hpp>
#define MRDOCS_ASSERT(x)
Use it as a statement, with a trailing semicolon, to check a precondition or invariant:
namespace mrdocs {
int
elementAt(std::vector<int> const& v, std::size_t i)
{
MRDOCS_ASSERT(i < v.size());
return v[i];
}
} // mrdocs
In debug builds, the assertion roughly expands to:
// 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 <file>" to stderr, and then the program
// traps (__builtin_trap on GCC/Clang, __debugbreak on
// MSVC).
static_cast<void>(!!(i < v.size()) ||
(assert_failed("i < v.size()",
__builtin_FILE(), __builtin_LINE()),
static_cast<void>(__builtin_trap(),
__builtin_unreachable()),
true));
In release builds (NDEBUG), it expands to:
// MRDOCS_ASSERT(i < v.size());
// The condition is dropped by the preprocessor. It's
// never compiled or evaluated.
static_cast<void>(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 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.
| Name | Description |
|---|---|
| x | The condition to check. |