Is there a way to add or edit the message thrown by assert? I'd like to use something like
assert(a == b, "A must be equal to B");
Then, the compiler adds line, time and so on...
Is it possible?
Is there a way to add or edit the message thrown by assert? I'd like to use something like
assert(a == b, "A must be equal to B");
Then, the compiler adds line, time and so on...
Is it possible?
A hack I've seen around is to use the &&
operator. Since a pointer "is true" if it's non-null, you can do the following without altering the condition:
assert(a == b && "A is not equal to B");
Since assert
shows the condition that failed, it will display your message too. If it's not enough, you can write your own myAssert
function or macro that will display whatever you want.
Another option is to reverse the operands and use the comma operator. You need extra parentheses so the comma isn't treated as a delimiter between the arguments:
assert(("A must be equal to B", a == b));
(this was copied from above comments, for better visibility)
Here's my version of assert macro, which accepts the message and prints everything out in a clear way:
#include <iostream>
#ifndef NDEBUG
# define M_Assert(Expr, Msg) \
__M_Assert(#Expr, Expr, __FILE__, __LINE__, Msg)
#else
# define M_Assert(Expr, Msg) ;
#endif
void __M_Assert(const char* expr_str, bool expr, const char* file, int line, const char* msg)
{
if (!expr)
{
std::cerr << "Assert failed:\t" << msg << "\n"
<< "Expected:\t" << expr_str << "\n"
<< "Source:\t\t" << file << ", line " << line << "\n";
abort();
}
}
Now, you can use this
M_Assert(ptr != nullptr, "MyFunction: requires non-null argument");
And in case of failure you will get a message like this:
Assert failed: MyFunction: requires non-null argument
Expected: ptr != nullptr
Source: C:\MyProject\src.cpp, line 22
Nice and clean, feel free to use it in your code =)
BOOST_ASSERT_MSG(expre, msg)
http://www.boost.org/doc/libs/1_51_0/libs/utility/assert.html
You could either use that directly or copy Boost's code. Also note Boost assert is header only, so you could just grab that single file if you didn't want to install all of Boost.
As zneak's answer convolutes the code somewhat, a better approach is to merely comment the string text you're talking about. ie.:
assert(a == b); // A must be equal to B
Since the reader of the assert error will look up the file and line anyway from the error message, they will see the full explanation here.
Because, at the end of the day, this:
assert(number_of_frames != 0); // Has frames to update
reads better than this:
assert(number_of_frames != 0 && "Has frames to update");
in terms of human parsing of code ie. readability. Also not a language hack.
assert is a macro/function combination. you can define your own macro/function, using __FILE__
, __BASE_FILE__
, __LINE__
etc, with your own function that takes a custom message
If the assert is done within a class, an alternative approach is to call a static predicate function with a self-describing name. If the assertion fails, the message will already contain the predicate's pretty and self-describing name.
E.g.:
static bool arguments_must_be_ordered(int a, int b) {return a <= b;}
void foo(int a, int b)
{
assert(arguments_must_be_ordered(a, b));
// ...
}
You may even want to make that predicate function public so that the class' user can verify the precondition themselves.
Even if assert
is not disabled for release builds, the compiler will likely inline the predicate if it's fairly trivial.
The same approach can be used for complex if
conditions needing a comment. Instead of a comment, just call a self-describing predicate function.
You could also just write your own custom assert function. A very simple example:
bool print_if_false(const bool assertion, const char* msg) {
if(!assertion) {
// endl to flush
std::cout << msg << std::endl;
}
return assertion;
}
int main()
{
int i = 0;
int j = 1;
assert(print_if_false(i == j, "i and j should be equal"));
return 0;
}
The assertion reads Assertion print_if_false(i == j, "i and j should be equal")
.
int x=10, y=25;
assert(x > y); // Add message along with this assert
Option 1) Since fprintf returns number of characters printed so we can or assert expression with !fprintf. Using stderr here since this is an error message
assert((x > y) || !fprintf(stderr, "Error: x %d is expected to be greater than y %d \n", x, y));
We can wrap this inside a macro for convinient use.
// Define macro over assert
#define assert_msg(cond, fmt, ...) assert( cond || !fprintf(stderr, fmt, ##__VA_ARGS__))
// Use above macro
assert_msg(x > y, "Error: x %d is expected to be greater than y %d \n", x, y);
Option 2) Define error message wrapped inside lambda.
auto err = [x, y] { fprintf(stderr, "Error: x %d should be greater than y %d \n", x, y); return false; };
assert((x > y) || err()); // Assert calls lambda func only when condition fails
Here is the dumped message.
Error: x 10 should be greater than y 25
File.cpp:10: int main(): Assertion `(x > y) || err()' failed.
Option 3) Or we can refine above solution to do it in one line with help of immediately invoked lambda
assert((x > y) || ([x, y] { fprintf(stderr, "Error: x %d is expected to be greater than y %d \n", x, y); return false; }()));
@Shakti Malik, thank you very much for your solution!
I have reduced it to:
#define ASSERT(cond, msg, args...) assert((cond) || !fprintf(stderr, (msg "\n"), args))
Excellent works)
For vc, add following code in assert.h,
#define assert2(_Expression, _Msg) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Msg), _CRT_WIDE(__FILE__), __LINE__), 0) )