在c++中可以将宏放在命名空间中吗?

4nkexdtk  于 2023-06-07  发布在  其他
关注(0)|答案(5)|浏览(320)

我的应用程序使用了不同于标准输出的另一种输出来记录信息,这就是为什么我编写了自己的Log()Error()Panic()Assert()函数。为了更好地组织这些内容,我将所有调试内容都包含在一个Debug名称空间中。
Assert()函数还提供源文件和行号会更有意义,这只能使用__LINE____FILE__宏。然而,这是非常不愉快的,效率低下等。必须始终指定这两个参数。
这就是我的代码看起来的样子:

namespace Debug {
   void Assert (int condition, std::string message, std::string file, int line);
}

我的问题是,是否可以在Debug命名空间中放置一个包含这两个参数的宏?像这样:

namespace Debug {
   void Assert_ (int condition, std::string message, std::string file, int line);
   #define Assert(a,b) Assert_(a, b, __FILE__, __LINE__)
}

// .... Somewhere where I call the function ....
Debug::Assert (some_condition, "Some_condition should be true");

// Output: Assertion failed on line 10 in file test.cpp:
//           Some_condition should be true

这是有效的C++吗?如果没有,有没有办法让它工作?

svujldwt

svujldwt1#

在c++中可以将宏放在命名空间中吗?

没有

#define是预处理器指令。除了删除注解(这意味着,在编译之前),宏被替换 * 在 * 其他任何东西之前。所以在宏被替换的时候,编译器对你的命名空间一无所知。
就像其他人说的那样,在你的情况下会很好。然而,这是你如何可以得到的问题:

namespace A
{
 void Assert_ (int condition, std::string message, std::string file, int line)
 {
     std::cout << "A";
 }
   #define Assert(a,b) Assert_(a, b, __FILE__, __LINE__)

}
namespace B
{
 void Assert_ (int condition)
 {
     std::cout << "B";
 }
   #define Assert(a,b) Assert_(a)

}

int main(int argc, char *argv[])
{
    A::Assert(0,"asdasd");
    B::Assert(0,"asdasd");
}

因此,虽然看起来定义是“在名称空间中”,但它们不是 *,并且最后一个#define将始终被使用,在这种情况下,这将导致编译时错误,因为main中的代码将被替换为:

A::Assert(0);
B::Assert(0);

而不是

A::Assert(0,"asdasd", _FILE_, _LINE_);
B::Assert(0);
wwtsj6pe

wwtsj6pe2#

不,预处理器根本不关心名称空间。事实上,预处理器至少在概念上在编译器看到任何东西之前运行。
对于我自己来说,我只是做了一个标准的ASSERT宏,并期望没有“健全的名称空间”有一个叫做ASSERT的东西。问题解决了如果我需要一个有自己的ASSERT的库,那么我仍然可以决定如何处理这个问题;然而,我目前使用的唯一一个带有自己的“assert”的库称之为BOOST_ASSERT或类似的东西……

gajydyqb

gajydyqb3#

namespace Debug
{
    void Assert_(int condition, std::string message, std::string file, int line);
    #define Assert(a,b) Assert_(a, b, __FILE__, __LINE__)
}

// .... Somewhere where I call the function ....
Debug::Assert (some_condition, "Some_condition should be true");

这个特定的用法将完全按照您的意愿执行,但是 * Assert宏绝不是Debug命名空间的一部分 *……就好像你做了

namespace Debug
{
    void Assert_(int condition, std::string message, std::string file, int line);
}

#define Assert(a,b) Assert_(a, b, __FILE__, __LINE__)

// .... Somewhere where I call the function ....
Debug::Assert (some_condition, "Some_condition should be true");

在这里,替换起作用不是因为AssertDebug名称空间中(它不在你的代码或这段代码中,预处理器不知道名称空间是什么)-它工作是因为Assert被识别为宏的标识符,Assert_的替换被完成,然后编译器恰好发现有一个Debug::Assert_所以,假设你在你的翻译单元后面的某个地方有一些完全不相关的代码:

my_object.Assert(my_functor);

宏替换仍然会产生一个编译时错误,说你对一个宏有错误的参数数量。假设不相关的代码是:

my_object.Assert(my_functor, "some text");

然后将其替换为:

my_object.Assert_(my_functor, "some text", __FILE__, __LINE__);

(另外,标准做法是在预处理器宏名称中不使用小写字母)。

ldioqlga

ldioqlga4#

你可以尝试__PRETTY_FUNCTION __宏来打印包括函数参数在内的所有命名空间。

wf82jlnq

wf82jlnq5#

是的,你的宏将扩展到你所期望的。

Debug::Assert (some_condition, "Some_condition should be true");

将被替换为

Debug::Assert_(some_condition, "Some_condition should be true", __FILE__, __LINE__)

相关问题