In pseudocode I would like to do this:
func(int a, int b) {
assert(a == b, std::format("values differ: {}!={}", a, b));
}
or
func(int a, int b) {
assert(a == b, [&a,&b]() { return std::format("values differ:{}!={}", a, b);});
}
because I want to printout a failure message that is more verbose. Is there some standard way to achieve this?
As far as I know there is no standard way in C++ to achieve exactly what you are asking for.
There is no standardized interface to add an additional message to assert errors. A portable way to include one is to use a comma operator provided it has not been overloaded, or use && with a string literal:
assert(("There are five lights", 2 + 2 == 5)); assert(2 + 2 == 5 && "There are five lights");
This obviously doesn't allow for runtime formatting.
If you really need to use runtime formatting you can either use some other assertion tools or create your own assert
macro or wrapper which could look like the following:
#include <string>
#include <format>
#include <cassert>
#define TO_WIDE_STR_(str) L ## str
#define TO_WIDE_STR(str) TO_WIDE_STR_(str)
#define myAssert(expr, msg) static_cast<void>(static_cast<bool>(expr) || (myAssertImpl(TO_WIDE_STR(#expr), msg, TO_WIDE_STR(__FILE__), __LINE__), false))
[[noreturn]] void myAssertImpl(const wchar_t* exprStr, const std::wstring& msg, const wchar_t* file, unsigned line) {
std::wstring str{ msg };
str += L" assert(";
str += exprStr;
str += L")";
_wassert(str.c_str(), file, line);
}
void func(int a, int b) {
myAssert(a == b, std::format(L"values differ: {}!={}", a, b));
}
Note that I compiled this using msvc on Windows and, since the assert
macros definition is not specified by the standard, this wrapper might not work for your environment.
You could also just ignore the native assert
implementation and write it completely yourself, following the description from cppreference.com - assert.
#include <string>
#include <source_location>
#include <cstdlib>
#include <iostream>
#define myAssert(expr, msg) static_cast<void>(static_cast<bool>(expr) || (myAssertImpl(#expr, msg), false))
[[noreturn]] void myAssertImpl(const char* exprStr, const std::string& msg, std::source_location location = std::source_location::current()) {
std::cerr << "Assertion failed!\n"
<< " > " << exprStr << '\n'
<< " > " << msg << '\n'
<< " > FILE: " << location.file_name() << '\n'
<< " > FUNCTION: " << location.function_name() << '\n'
<< " > LINE: " << location.line() << '\n'
<< " > COLUMN: " << location.column() << '\n';
std::abort();
}