I have a logger that is used multiple place in the code that takes a string and prints it and another function that tells me whether the log is enabled:
void log_msg(std::string const& msg);
bool is_log_enabled();
When the log is disabled I want to avoid the (possible expensive) string construction, like here:
void some_func()
{
log_msg(std::string("some_string: ") + std::to_string(500) + std::string(" even more string...");
}
When the above is run, the whole string will be constructed before being passed to the log_msg
function, which might not even use it if the log is not enabled.
I know I can use:
#define log(msg) \
if (is_log_enabled()) { \
log_msg(msg); \
}
To avoid the string construction, but is there away to do this without the use of macros, since they are in general not recommended to use?
Could inlining the function possibly fix the issue
void inline log_msg(std::string const& msg) \
if (is_log_enabled()) { \
log_msg(msg); \
}
or is this guaranteed to construct the function argument (i.e., constructing the string even when the log is disabled)?
Your approach with the function will construct the std::string
regardless of whether or not the log is enabled. Of course a compiler might optimize though.
C++ doesn't have lazily-evaluated function arguments. However, they can be emulated by passing a lambda that is invoked by the function:
void log_msg(auto generator) {
if (is_log_enabled())
real_log_msg(std::invoke(generator));
}
//...
log_msg([&]{ return std::string("some_string: ") + std::to_string(500) + std::string(" even more string..."); });
Unfortunately there is currently no more concise syntax for such a single-expression lambda. Hopefully it will come in a future C++ revision. However, you could of course write a macro for that specific, much more general, purpose.