是否可以在 C++ 的命名空间中放置宏?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11791187/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to place a macro in a namespace in c++?
提问by Tibi
My application uses another output than the standard output for logging information, which is why I wrote my own Log()
, Error()
, Panic()
and Assert()
functions. To organize things nicely, I enclose all the debugging stuff in a Debug
namespace.
我的应用程序使用比标准的输出记录的信息,这就是为什么我写我自己的另一个输出Log()
,Error()
,Panic()
和Assert()
功能。为了很好地组织事情,我将所有调试内容都包含在一个Debug
命名空间中。
It would make more sense for the Assert()
function to also provide a source file and line number, which is only possible using the __LINE__
and __FILE__
macros. However, it is pretty unpleasant, inefficient etc... to always have to specify these two parameters.
该Assert()
函数还提供源文件和行号会更有意义,这只能使用__LINE__
和__FILE__
宏。然而,总是必须指定这两个参数是非常令人不快的、低效的等等。
So this is how my code would look like:
所以这就是我的代码的样子:
namespace Debug {
void Assert (int condition, std::string message, std::string file, int line);
}
My question is, is it possible to place a macro which includes those two parameters inside the Debug
namespace? Like this:
我的问题是,是否可以在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
Is this valid c++? If not, is there any way of making this work?
这是有效的 C++ 吗?如果没有,有没有办法使这项工作?
回答by SingerOfTheFall
#define
is a preprocessor directive. The macros are being replaced beforeanything else apart from removing comments (which means, before compilation). So at the time macros are replaced, the compiler knows nothing about your namespaces.
#define
是一个预处理器指令。除了删除注释(这意味着在编译之前)之外,宏会在其他任何事情之前被替换。因此,在替换宏时,编译器对您的命名空间一无所知。
As other people state, in your case it will be fine. However, This is how you can get problems:
正如其他人所说,在你的情况下会很好。但是,这是您遇到问题的方式:
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");
}
So while it looks like the defines are "in the namespaces", they are not, and the last #define
will be always be used, which in this case will lead to a compile-time error, because the code in main will be replaced by:
因此,虽然看起来定义是“在命名空间中”,但它们不是,并且#define
将始终使用最后一个,在这种情况下将导致编译时错误,因为 main 中的代码将被替换为:
A::Assert(0);
B::Assert(0);
instead of
代替
A::Assert(0,"asdasd", _FILE_, _LINE_);
B::Assert(0);
回答by Tony Delroy
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");
This specific usage would do exactly what you want, but the Assert macro is in no way part of the Debug namespace... it's exactly as if you'd done:
这种特定的用法完全符合您的要求,但是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");
Here, the substitution works not because Assert
was in the Debug
namespace (it's not in your code or this code, and the preprocessor has no clue what namespaces are about) - it works because Assert
is recognised as an identifier for a macro, the substitution of Assert_
is made, then later the compiler proper happens to find there's a Debug::Assert_
So, say you have somewhere later in your translation unit you have some completely unrelated code:
在这里,替换起作用不是因为Assert
在Debug
命名空间中(它不在您的代码或这段代码中,并且预处理器不知道命名空间是关于什么的)-它起作用是因为Assert
被识别为宏的标识符,替换Assert_
了,然后编译器本身碰巧发现有一个Debug::Assert_
因此,假设您稍后在翻译单元中的某个地方有一些完全不相关的代码:
my_object.Assert(my_functor);
The macro substituion will still kick in to produce a compile-time error saying you have the wrong number of arguments to a macro. Say the unrelated code was instead:
宏替换仍然会产生编译时错误,说明宏的参数数量错误。说不相关的代码是:
my_object.Assert(my_functor, "some text");
Then that would be replaced with:
那么这将被替换为:
my_object.Assert_(my_functor, "some text", __FILE__, __LINE__);
(Separately, it's standard practice not to use lower case letters in preprocessor macro names).
(另外,标准做法是不在预处理器宏名称中使用小写字母)。
回答by Christian Stieber
No, the preprocessor doesn't care about namespaces at all. In fact, the preprocessor runs, at least conceptually, before the compiler sees anything.
不,预处理器根本不关心命名空间。事实上,预处理器在编译器看到任何东西之前运行,至少在概念上是这样。
For myself, I just do a standard ASSERT macro, and expect that no "sane namespace" has something called ASSERT. Problem solved. Should I require a library that has an ASSERT of its own then I can still decide how to deal with this; however, the only library that I'm currently using with its own "assert" calls it BOOST_ASSERT or something like that...
就我自己而言,我只是做一个标准的 ASSERT 宏,并期望没有“理智的命名空间”具有称为 ASSERT 的东西。问题解决了。如果我需要一个拥有自己的 ASSERT 的库,那么我仍然可以决定如何处理这个问题;然而,我目前使用的唯一一个带有自己的“断言”的库称之为 BOOST_ASSERT 或类似的东西......
回答by kurthaha
You can try __PRETTY_FUNCTION __ macro to print all the namespaces including function arguments.
您可以尝试 __PRETTY_FUNCTION __ 宏来打印包括函数参数在内的所有命名空间。
回答by Luchian Grigore
Yes, and your macro would expand to exactly what you expect.
是的,您的宏将扩展到您所期望的。
Debug::Assert (some_condition, "Some_condition should be true");
would be replaced by
将被替换
Debug::Assert_(some_condition, "Some_condition should be true", __FILE__, __LINE__)