是否可以在 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 15:33:11  来源:igfitidea点击:

Is it possible to place a macro in a namespace in c++?

c++macrosnamespaces

提问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 Debugnamespace.

我的应用程序使用比标准的输出记录的信息,这就是为什么我写我自己的另一个输出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 Debugnamespace? 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

#defineis 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 #definewill 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 Assertwas in the Debugnamespace (it's not in your code or this code, and the preprocessor has no clue what namespaces are about) - it works because Assertis 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:

在这里,替换起作用不是因为AssertDebug命名空间中(它不在您的代码或这段代码中,并且预处理器不知道命名空间是关于什么的)-它起作用是因为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__)