是否可以在c ++中的命名空间中放置一个宏?

时间:2012-08-03 07:27:15

标签: c++ macros namespaces

我的应用程序使用另一个输出而不是标准输出来记录信息,这就是我编写自己的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 ++吗?如果没有,有没有办法使这项工作?

5 个答案:

答案 0 :(得分:27)

#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");
}

因此,虽然名称空间中的定义是&#34;&#34;,但它们不是,并且将始终使用最后的#define,其中case将导致编译时错误,因为main中的代码将替换为:

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

而不是

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

答案 1 :(得分:2)

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命名空间中(它不在你的代码或这段代码中,并且预处理器不知道命名空间是什么) - 它的工作原理是因为{ {1}}被识别为宏的标识符,Assert被替换,然后编译器正好发现有一个Assert_ 所以,假设你在翻译单元的某个地方有一些完全不相关的代码:

Debug::Assert_

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

my_object.Assert(my_functor);

然后将替换为:

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

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

答案 2 :(得分:1)

不,预处理器根本不关心名称空间。事实上,预编译器在编译器看到任何内容之前至少在概念上运行。

对于我自己,我只是做一个标准的ASSERT宏,并期望没有“理智的命名空间”有一个叫做ASSERT的东西。问题解决了。我是否需要一个拥有自己的ASSERT的库,那么我仍然可以决定如何处理这个问题;但是,我目前使用自己的“断言”的唯一一个库称它为BOOST_ASSERT或类似的东西......

答案 3 :(得分:0)

是的,您的宏将扩展到您期望的结果。

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

将被

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

答案 4 :(得分:0)

您可以尝试使用__PRETTY_FUNCTION __宏来打印所有名称空间,包括函数参数。