Assert with dynamic message? - c++

In my program I want to use asserts that show an error message. Apart from the well known workarounds for C and C++ there's the "real" solution as BOOST offers BOOST_ASSERT_MSG( expr, msg ) (see also assert() with message)
But a static message isn't enough for me, I also want to show sometimes the failed variables, e.g. in a case like
BOOST_ASSERT_MSG( length >= 0, "No positive length found! It is " << length )
As you can see I'd like to format the message "string" as an stringstream or ostream as that'd allow me to easily show custom types (assuming I've defined the relevant formating function).
The problem here is that BOOST_ASSERT_MSG is by default requiring a char const * so that's not compatible.
Is there a way to redefine / overload assertion_failed_msg() in such a way that using a stream as message will work? How?
(My naive approach failed as the compiler first wanted to do an operator<<("foo",bar) on the message itself...)

You could define your own macro
#define ASSERT_WITH_MSG(cond, msg) do \
{ if (!(cond)) { std::ostringstream str; str << msg; std::cerr << str.str(); std::abort(); } \
} while(0)

It's relatively trivial to achieve this.
BOOST_ASSERT_MSG( length >= 0, (std::stringstream() << "No positive length found! It is " << length).str().c_str() )

Here is a solution that doesn't rely on macros. Instead, it uses a tiny bit of templating and lambda syntax.
template<typename Fn>
void assert_fn( bool expr, Fn fn) {
if (!expr) {
fn();
abort();
}
}
The argument fn can be any callable.
For instance you can call it like so:
assert_fn( a==b, [&](){ cout << "Assertion failed: a="<< a <<
" is different from but b=" << b << endl; } );
The advantage is that the output is that you are not calling abort explicitly and the output is fully customizable. The this advantage, of course, are the seven extra characters of lambda function boilerplate: [&](){} )

I use the BOOST_ASSERT_MSG with my own wrapper around it, so that specifying the assert message with multiple operator<< seems less complex.
#if defined ASSERT_ENABLED
#define ASSERT(cond, msg) {\
if(!(cond))\
{\
std::stringstream str;\
str << msg;\
BOOST_ASSERT_MSG(cond, str.str().c_str());\
}\
}
#else
#define ASSERT(...)
#endif
usage example, provide custom message like you are outputting to cout:
ASSERT(execSize == (_oldSize - remaining), "execSize : " << execSize << ", _oldSize : " << _oldSize << ", remaining : " << remaining);
What it does is, if ASSERT_ENABLED is defined,enable the assertion messages. if(!(cond)) part is optimization, which avoids the costly string operations specified by macro parameter msg, if cond is true

If you are working on Windows only, you can take a look to assert macro. Under the hood it uses _wassert. You can write your own assert macro using it. For instance in my case if I get some point, I want to show assert without conditions:
#ifdef DEBUG
const std::wstring assert_msg = /* build the string here */;
_wassert(assert_msg.c_str(), _CRT_WIDE(__FILE__), (unsigned)(__LINE__));
#endif
I think on other OS you can do the same trick, just take look at assert macro.

Related

Create constrexpr function with macro behaviour

I have a macro function which works as you would expect:
#define PRECONDITION(testBool) ( !(testBool) ? \
( fprintf(stderr, "%s:%i: Precondition '%s' failed.\n", \
__FILE__, __LINE__, #testBool), \
exit(1) ) : void(sizeof(0)) )
This is great, since I can create nice assertions:
PRECONDITION(5 > 6); // prints "<file>:<line>: Precondition '5 > 6' failed."
While this works, I'm trying to learn a better and more modern way of doing this,
using constexpr, so I can have type safety, use std::err <<.
However, I have not been able to find a source stating how to do this / whether or not it
is actually possible, so I ask here. What I image is something along the lines of:
constexpr void PRECONDITION(bool testBool)
{
if(testBool) { return; }
std::cerr << __SOME_MAGIC__ << ":" << __SOME_MAGIC__ << ":"
<< "Precondition '" << __SOME_MAGIC__ << "' failed." << std::endl;
}
Is it possible to achieve this behaviour?
Short answer: No.
Long answer: Macro expansion is just a textual transform of the source code. Once transformed by macro definitions, source code is "given" to the compiler to compile it. So, macros are expanded before compiler has even started doing its job while constexpr functions are executed on compile time. Therefore, macros and constexpr expressions are 2 different things.

Enable debug print statements if compiled with debug flag

Let's say I have a project with many functions. For debugging purpopses, I want each one of them print out a diagnostic message (or a few) when called:
int f(int arg) {
cerr << "f() called with argument" << arg << endl;
int ret = 42;
cerr << "f() returned " << ret << endl;
return ret;
}
and so on. In one function, there may be as many as five to six messages printed out on cerr. I want to be able to disable them unless a debug flag (like NDEBUG) is set. One thing I could do is wrap each cerr statement with an if-statement.
#ifdef NDEBUG
const bool DEBUG_ON = true;
#else
const bool DEBUG_ON = false;
#endif
int f(int arg) {
if (DEBUG_ON) {
cerr << "f() called with argument" << arg << endl;
}
int ret = 42;
if (DEBUG_ON) {
cerr << "f() returned " << ret << endl;
}
return ret;
}
But it can get really tedious and, in the end, virtually unreadable with a couple dozens of such statements. My idea was to replace cerr with a custom object with an overloaded << operator which would send any arguments passed to it "into the void" like this:
class NullOutStream {
public:
NullOutStream operator<<(...) {
return *this;
}
};
NullOutStream debug_out;
#ifdef NDEBUG
#define debug_out cerr
#else
#define debug_out debug_out
#endif
Although it works perfectly, it doesn't seem very elegant. Is there a standard/nicer way to accomplish this?
There is no "standard" way to do this. There are many logging/assertion libraries that deal with similar issues, and there are different approaches to solve this. A few things to keep in mind:
It may or may not be desirable to keep the side effects of your log statement (as yours does). For example, if you did something like this:
debug_out << ++i;
This would increment i no matter whether you are in debug mode or not. This is probably desirable in this case. Conversely, if you do this:
debug_out << some_object.expensive_to_string_operation();
This would call expensive_to_string_operation() even when you are not in debug mode. This is probably not desirable in this case.
This would not happen if you used printf-style debug macro, e.g. something like this:
#ifdef NDEBUG
#define logf(...)
#else
#define logf(...) printf(__VA_ARGS__)
#endif
The reason being that when in non-debug mode, the arguments would be removed by the preprocessor.
You may want to do other things before or after each log statement, e.g. record a time stamp, flush a log file etc. It is possible to do this with streams by using destructor tricks, but it is more complicated to implement. It is much easier to do this using a function call, e.g. something like this:
#define log(msg) printf("%s: %s\n", timestamp(), msg)
You may want to record file name / line number with your logs. Again, this is easier to do with a function call than with a stream.
Streams may be better if you want custom formatting by object type - the printf interface doesn't lend itself to that very well.
I would recommend to have a look at some existing logging libraries to get an idea of different approaches. I suggest looking at Google's glog library because it has an interesting combination of using streams while retaining the ability to do 'per call' things (e.g. record time stamps, line numbers etc).

Concatenating a string and passing as a parameter?

I wrote my own logger that I can use as follows:
LOG("This is the number five: " << 5 << ".");
I'd like to write an error checking method that simply takes a return code, checks if it's an error, and if so prints an error message
Thus, I'd like to turn:
if(result == -1)
{
LOG("ERROR! We got a result of: " << result << ".");
// Do some other stuff
}
into:
checkForError(result, "ERROR! We got a result of: " << result << ".");
void checkForError(int result, SomeStringType message)
{
if(result == -1)
{
LOG(message);
// Do some other stuff
}
}
is this possible? I've tried passing it as a char*, a std:string, and as a stringstream, but I can't seem to get it to work correctly
Is there any way to do this so I'm simply concatenating the error message in the call to the function?
Yes, it's possible. You could do it like this:
#define LOG(X) \
do { \
std::ostringstream log_stream; \
log_stream << X; \
LOG::log_internal(log_stream.str()); \
} while (0)
where LOG::log_internal might be declared in your logger header like
struct LOG {
static void log_internal(const std::string &);
};
The main drawback of this is that it's not the most hygienic macro ever -- if the argument X contains semicolons, then you could have additional statements executed inside the macro's scope, and there won't be a compiler error. This macro is far from cryptic though in my opinion, and fortunately you don't actually have to worry about an attacker performing SQL-injection-esque attacks against your macros.
I use loggers that basically look like this in my projects, and I learned to do it this way from other projects. (Actually the one I use is a little more developed, it also passes __FILE__ and __LINE__ to the LOG::log_internal function, and there's log channels and log levels which may or may not be active etc. etc...)

Lazy logging in C++

Let's suppose that we have several levels of logging: trace, debug, info, error.
I was wondering if there is a way to write the following code:
enum log_level = {trace, debug, info, error};
log_level global_log_level = info;
void log(log_level level, string& message){
if (level >= global_log_level){
std::cout << message << std::endl;
}
}
string create_message(){
...
}
log_level level = debug;
log (level, create_message());
without create_message being called if level is smaller that global_severity_level. Indeed, create_message can be quite long, and no matter what it creates a string. If there are a lot of "debug" logs, those ones can become a substantial overhead when running in non-debug mode.
I know it is possible to do so if the function "log" is a macro, calling create_message() only if severity > minimal_severity; but isn't there another way to do this without macros?
EDIT
In the above, I didn't specify create_message, because it could be anything, in particular:
log(level, "Created object " + my_object.getName());
In this case, is there a way to write log such that the full string is not created, in a relatively transparent way for the programmer calling log?
Many thanks
Similar to #sftrabbit, but as suggested by #ipc.
Use a template to avoid the std::function machinery, and the compiler may be able to inline this and thus it hopefully will end up being faster.
template< typename F >
void log(log_level level, F message_creator){
if (level >= global_log_level){
std::cout << message_creator() << std::endl;
}
}
There are several alternatives. An interesting one is to pass create_message as a std::function<std::string()> and call it from within log:
void log(log_level level, std::function<std::string()> message_creator){
if (level >= global_log_level){
std::cout << message_creator() << std::endl;
}
}
Then you would call it like so:
log(level, create_message);
This can work with arbitrary expressions as arguments if you wrap them in a lambda:
log(level, [&](){ return "Created object " + my_object.getName(); });
If you really don't want to argument to be evaluated at all (as you've described in the comments), then you'll need to check the level outside of the call:
if (level >= global_log_level) {
log(level, create_message());
}
#sftrabbit answer is prefered. But just if you dont want to change log(), you can call it:
log (level, (level >= global_log_level)? create_message() : "");
You can create a macro
#define log(level, message) { \
if(level >= global_log_level) {\
cout &lt&lt message; }}
Now if you call log(debug, create_message()); create_message will be called only if debug level is the desired one.

macros with variable number of arguments

I've been developing application which uses logging mechanism, and I implemented sort of printf function which takes various number of arguments and prints to log certain message, what I want is to add a function name to this function, but I dont what to write this argument in each function call.
So I decided to write a macros, turns out it not so easy
#define WriteToLogParams(szMessage, nLogLevel, param1, param2) WriteToLogParamsFunc(szMessage, __FUNCDNAME__, nLogLevel, param1, param2)
First I thought that there is some kind of macros overloading and I can easily do it , but turns out if I write another macros with the same name but with different number of argument it wont compile. So to make it work I should make each macros name unique.
So is there are any intelligent way to do this?
Thank you on advance.
You can use __VA_ARGS__ macro
for example:
WriteToLogParamsFunc(const char *__file, int __line, const char* __func, int nLogLevel, const char *szMessage, ...);
#define WriteToLogParams(nLogLevel, szMessage, ...) WriteToLogParamsFunc(__FILE__, __LINE__, __FUNCTION__, nLogLevel, szMessage, __VA_ARGS__ )
I believe there are some preprocessors that support variadic macros but I'm not sure if it's a standard and there definately are compilers that don't support it so it's not portable.
However, instead of trying to have a variable number of parameters, have only one parameter. This is what I have done:-
#define WriteToLogParams(args) WriteToLogParamsObject::Instance (__FUNCDNAME__) << args
where the WriteToLogParamsObject is a class that is created by the static member Instance and has overloaded streaming operators. This gives you the advantages that using these operators has, such as putting streaming overloads into classes:-
class SomeClass
{
static friend WriteToLogParamsObject &operator << (WriteToLogParamsObject &stream, const SomeClass &item_to_log)
{
stream << "member1 = " << item_to_log.m_member1 << ", member2 = " << item_to_log.m_member2;
// and so on (syntax might be off)
return stream;
}
};
And to use the macro:-
WriteToLogParams ("some message " << some_value << " another bit of text " << another_value << " and so on");