Search code examples
c++preprocessorassertionc++20

Implement assert without preprocessor in C++20


C++ knows assert() which allows runtime checks that compile to nothing in dependence of NDEBUG.

I would like to replace that macro using compiler-code and avoiding the preprocessor. I need to do the following:

  • Break or terminate if expressions evaluates to false
  • Log the code line where the assert is called
  • Discard the check and the passed expression for NDEBUG builds

Breaking/terminating the application is easy.

In C++20 there is std::experimental::source_location which I can use to get the code location of the assertion.

A compile time conditional could be done using requires or constexpr if

However I do not know how I could avoid the evaluation of the expression. When implementing myAssert(expression) as a function, I need to pass the expression result as a function argument which means it is evaluated anyway, even if the parameter is not used inside the function.

Is there a way to solve this in C++20?

EDIT: A templated example:

template <typename T> requires (gDebug)
void assertTrue(const T& pResult, const std::experimental::source_location& pLocation) noexcept
{
   if (!static_cast<bool>(pResult))
   {
      // error handling
   }
}

template <typename T> requires (!gDebug)
void assertTrue(const T&) noexcept
{
}

Solution

  • I suppose you are talking about the case when you disabled debugging and you want the function to be a noop. I see 2 options:

    You can use a macro. Macros can be misused, but they have their place and "passing an expression" without evaluating it is a case for a macro.

    Alternatively, pass a callable that returns the result you want to assert for. Only call it when gDebug == True:

    template <typename F> requires (gDebug)
    void assertTrue(const F& f, const std::experimental::source_location& pLocation) noexcept
    {
       if (!static_cast<bool>(f()))
       {
          // error handling
       }
    }
    

    Though this will make the call rather verbose. For example one that fails always:

    assertTrue( [](){ return false; });