Lazy entry in C ++

Suppose we have several levels of logging: tracing, debugging, information, 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 calling create_message if the level is less than global_severity_level. Indeed, create_message can be quite long, and regardless of what it creates the string. If there are many "debug" logs, they can become significant overhead when working in non-debug mode.

I know that this is possible if the "log" function is a macro that calls create_message () only if the severity> minimum_severity; but is there no other way to do this without macros?

EDIT

In the above example, I did not 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 record the log so that the complete line is not created in a relatively transparent way for the programmer’s call log?

Many thanks

+8
c ++ logging lazy-evaluation
source share
4 answers

Like @sftrabbit, but as suggested by @ipc.

Use a template to avoid the std :: function mechanism, and the compiler can embed it, and hopefully it will be faster.

 template< typename F > void log(log_level level, F message_creator){ if (level >= global_log_level){ std::cout << message_creator() << std::endl; } } 
+5
source share

There are several alternatives. It is interesting to pass create_message as std::function<std::string()> and call it from 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 that:

 log(level, create_message); 

This can work with arbitrary expressions as arguments if you wrap them in lambda:

 log(level, [&](){ return "Created object " + my_object.getName(); }); 

If you really don't want the argument to be evaluated at all (as you described in the comments), you need to check the level outside of the call:

 if (level >= global_log_level) { log(level, create_message()); } 
+6
source share

@sftrabbit's answer is preferable. But if you do not want to change log (), you can call it:

 log (level, (level >= global_log_level)? create_message() : ""); 
+1
source share

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 only be called if the debug level is desired.
+1
source share

All Articles