创建可以像函数一样使用的日志宏



我有一个由多个函数组成的日志宏,它看起来像这样:

#define MY_LOG(s) { myMutex.lock(); std::cout << __PRETTY_FUNCTION__ << " (" << __LINE << ")" << s << std::endl; myMutex.unlock(); }

我希望能够调用宏,使其看起来类似于调用普通函数。我想让它以分号结束

在大多数情况下确实有效。下面是一个例子:

if (1 == 1)
MY_LOG("ok " << 1);

很好。没有问题。但在这种情况下不起作用:

if (1 == 1)
MY_LOG("1 == 1");
else
c++;

我得到一个错误,有一个else没有前面的if。有可能解决这个问题吗?

之所以有效,是因为在大多数情况下,一个额外的;将被编译器忽略。你写的是{ ... };

对于if/else则不是这样。考虑以下代码:

if (cond1)
if (cond2) something();
else {
...
}

如果额外的;不能关闭内部的if,那么您必须添加else { }。C/c++的设计者使用;作为它的简化版本。


现在要修复您的宏,您必须以需要;但没有其他效果的东西结束。这个问题的解决方案是为什么在宏中使用明显没有意义的do-while和if-else语句?

#define mymacro(parameter) do{/**/} while(0)

但是随着std::source_location的引入,整个宏在现代(从c++20开始)c++中已经过时了。让它成为一个实际的函数:

void log(const std::string_view message,
const std::source_location location = 
std::source_location::current())
{
std::lock_guard<std::mutex> lock(myMutex);
std::cout << "file: "
<< location.file_name() << "("
<< location.line() << ":"
<< location.column() << ") `"
<< location.function_name() << "`: "
<< message << 'n';
}

通常的解决方案是这样使用do { ... } while(0):

#define MY_LOG(s) do {                                                            
std::lock_guard<std::mutex> lock(myMutex);                                
std::clog << __PRETTY_FUNCTION__ << " (" << __LINE__ << ")" << s << 'n'; 
} while(false)

注意std::lock_guard而不是手动锁定。

但是使用可变宏、可变函数模板和c++ 20std::source_location,你可以做出更通用的东西:

#include <iostream>
#include <mutex>
#include <sstream>
#include <source_location>
template<class... Args>
void my_log(const std::source_location loc, Args&&... args)
{
static std::mutex myMutex;
std::ostringstream os;      // used to build the logging message
os << loc.function_name() << " (" << loc.line() << "):" << std::boolalpha;
// fold expression:
((os << ' ' << args), ...); // add all arguments to os

std::lock_guard<std::mutex> lock(myMutex); // use a lock_guard
std::clog << os.str();                     // and stream
}
// this just forwards the source location and arguments to my_log:
#define MY_LOG(...) my_log(std::source_location::current(), __VA_ARGS__)
int main() {
MY_LOG("A", 1, 2, 'B');
}

演示

最新更新