我的应用程序使用另一个输出而不是标准输出来记录信息,这就是我编写自己的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 ++吗?如果没有,有没有办法使这项工作?
答案 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");
在这里,替换不是因为Assert
在Debug
命名空间中(它不在你的代码或这段代码中,并且预处理器不知道命名空间是什么) - 它的工作原理是因为{ {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 __宏来打印所有名称空间,包括函数参数。