【问题标题】:Is it possible to place a macro in a namespace in c++?是否可以在 C++ 的命名空间中放置一个宏?
【发布时间】:2012-08-01 05:37:42
【问题描述】:

我的应用程序使用标准输出之外的另一个输出来记录信息,这就是我编写自己的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++ 吗?如果没有,有什么办法可以做到这一点?

【问题讨论】:

  • 这会起作用,但宏不是命名空间的一部分。
  • @PaulR 所以换句话说,如果我省略了Debug::,宏仍然可以工作吗?
  • 不 - 你仍然需要命名空间前缀(因为你所做的只是在预处理器中将 Assert 转换为 Assert_) - 问题是如果你在命名空间之外使用 Assert那么它仍然会被翻译,这可能不是你想要发生的。

标签: c++ macros namespaces


【解决方案1】:

#define 是一个预处理器指令。除了删除 cmets(这意味着在编译之前)之外,宏正在被替换之前。因此,在替换宏时,编译器对您的命名空间一无所知。

正如其他人所说,在你的情况下它会很好。但是,这就是您遇到问题的方式:

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);

【讨论】:

  • @Tibi - 方法是不要使用macros。使用在命名空间中定义的常量或内联函数。
  • 为什么它不起作用。 Assert 将使用额外的 2 个参数扩展为 Assert_。有什么问题?
  • @LuchianGrigore - “问题”在标题中:“是否可以在 c++ 中的命名空间中放置宏?”
  • @KirilKirov 你让我有点迷失了方向。调用函数时如何使用常量和内联函数获取行和源文件?
  • @KirilKirov 我不明白这是个问题。您可以将宏放在任何地方。
【解决方案2】:

是的,您的宏将扩展为您所期望的。

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

将被替换为

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:
      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__);
      

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

      【讨论】:

      • Separately, it's standard practice not to use lower case letters in preprocessor macro names。我知道,但以 windows api 为例。有很多宏不尊重这种做法,以至于调用了另一个函数的 ascii/unicode 版本。
      【解决方案5】:

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

      【讨论】:

      • 虽然这可能是解决问题的宝贵提示,但答案确实需要证明解决方案。请edit 提供示例代码来说明您的意思。或者,考虑将其写为评论。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-01
      • 1970-01-01
      相关资源
      最近更新 更多