C++宏解析问题

C++ macro parsing issue

我正在尝试使用宏在 ostringstream 中本地排队单个日志行,然后在该行结束时转储该 ostringstream 的全部内容。但是,我仍想使用流插入语法。所以我想像这样打开一个日志行:

std::cerr << "Some error in my function.  Code is " << errCode << " exiting" << std::endl;

...进入这个

SERR("Some error in my function.  Code is " << errCode << " exiting);

我有一些简单但效果很好的东西。也就是说,直到我将其放入 if-else 语句中。显然我的微距不好,但我不知道该怎么做。

这里是一个小的示例程序,用来说明问题。:

#include <iostream>
#include <sstream>
#define SERR(x)     { std::ostringstream _s; ; _s << x << std::endl; std::cerr << _s.str(); }

int main()
{
    std::cout << "Hello World!\n"; 
    bool val = false;
    if (val)
        SERR("No error");
    else
        SERR("Error"); 
}

我在这个示例中从编译器得到的错误信息是:

1>c:\users\joe\source\repos\consoleapplication5\consoleapplication5\consoleapplication5.cpp(15): error C2181: illegal else without matching if

知道我这里有什么问题吗?

(请注意,我现在不在可以使用第 3 方日志记录解决方案的地方,所以它必须像这样简单。我可以让所有这些保持正常 std::cerr/std::cout/std::clog 消息,如果必须的话,但我更喜欢一些简单的东西,以尽量减少我的多线程应用程序中日志消息交织的机会。)

试着展开它,看看你会得到什么:

#include <iostream>
#include <sstream>

int main()
{
    std::cout << "Hello World!\n"; 
    bool val = false;
    if (val)
        { std::ostringstream _s; ; _s << "No error" << std::endl; std::cerr << _s.str(); };
    else
        { std::ostringstream _s; ; _s << "Error" << std::endl; std::cerr << _s.str(); };
}

注意 { } 块如何以 ; 终止?

如果您需要宏,您应该始终使用 do { } while (0) 编写它,如下所示:

#define SERR(x)                                     \
    do {                                            \
        std::ostringstream _s;                      \
        _s << (x) << std::endl;                     \
        std::cerr << _s.str();                      \
    } while (0)

这不仅解决了您的问题,而且还强制在宏后添加 ;。否则人们可以通过两种方式使用它:

SERR("foo")  // without ;
...
SERR("bar"); // with ;