【问题标题】:Conflict between a namespace and a define命名空间和定义之间的冲突
【发布时间】:2009-09-04 08:19:05
【问题描述】:

我有这个严重的问题。我在这样的 2 个命名空间中有一个枚举:

namespace FANLib {
namespace ERROR {

    enum TYPE {

        /// FSL error codes
        FSL_PARSER_FILE_IERROR,...

在我的代码中的其他地方,我这样使用它:

FANLib::Log::internalLog(FSLParser::FILE_IERROR, file_ierror, true, FANLib::ERROR::FSL_PARSER_FILE_IERROR);

所有编译都很好,但如果我碰巧包含“windows.h”,我会出错!问题出在“WinGDI.h”中,它有这一行:

#define ERROR               0

并让编译器认为,在 FANLib::... 之后,有一个零! 我得到的错误是:

错误 1 ​​错误 C2589: 'constant' : '::' 右侧的非法令牌

错误 2 错误 C2059:语法错误:'::'

错误 3 错误 C2039:“FSL_PARSER_FILE_IERROR”:不是“全局命名空间”的成员

有什么我可以做的,而不必因为一些粗心的#define 而改变我的命名空间?我在另一篇文章中读到我可以#undef ERROR,但这有多安全?

【问题讨论】:

    标签: c++ namespaces c-preprocessor


    【解决方案1】:

    通常,您应该避免使用全大写标识符,因为它们用于宏。在这种情况下,我会重命名命名空间。

    (作为旁注,<windows.h>#defines 其他类似GetPrinter 的东西确实很烦人。我通常会选择#undef。它也有助于只在.cpp 文件中包含<windows.h>并确保受标头影响的范围尽可能小。)

    【讨论】:

    • 你提出了几个非常好的观点。不幸的是,我仍然只能给你的答案一票。
    • 我要添加“标准接受的约定”是所有大写的标识符都是宏。
    • Windows.h 采用所有“标准接受的约定”,将它们扔出窗口,并在其上声明宏。但是,是的,很好的建议。除了#defines 之外,不要使用全大写,也不要让 windows.h 在标题中可见。
    【解决方案2】:

    重命名命名空间是最干净、最安全、最可互操作的解决方案。

    【讨论】:

      【解决方案3】:

      因为ERROR 的名称太常见且含糊不清,所以加入了“重命名您的命名空间”的潮流。查找更具描述性的内容。

      【讨论】:

        【解决方案4】:

        我认为如果你#undef 它不会有问题。但是,您必须在使用枚举和 windows.h 的任何地方都这样做。最好的办法是重命名您的命名空间。

        【讨论】:

          【解决方案5】:

          您可能希望重构代码,以便 #include 仅在必要时出现。 “正确”的方式甚至可能涉及制作单独的文件和标头,其中包含您将从 windows.h 调用的函数的接口

          但是,如果您只是想要一个简单的修复并且担心#undef ERROR 的副作用,只需在完成声明后重新定义 ERROR:

          #undef 错误 命名空间错误 { #定义错误 0

          每次引用 ERROR 时都必须这样做(而不是在字符串中)。

          话虽如此,如果您只是未定义的错误应该没问题。从那时起,它只会影响 C 预处理器如何处理 ERROR(或者更确切地说是如何不处理)。

          顺便说一句,我通常看到所有大写字母的名称仅用于指定常量,而不用于类型和命名空间。如果我是你,我会重新考虑我的命名约定..

          【讨论】:

          • 坏主意;微软在较新的 SDK 版本中更改#define 的情况并非闻所未闻。即使是常量也会发生这种情况(尽管 ERROR 可能不会受到影响)
          • 你是对的,这不是一个很好的做法,并且很容易导致以后很难调试副作用,假设标签的值将始终是给定的常量。但在我的辩护中,这不是我的第一个建议,也不是我的最后一个建议,我从来没有说过任何关于一个好的修复,我说这是一个简单的修复(或快速修复) - 这些类型的修复通常会导致难以调试副作用!
          【解决方案6】:

          正如其他人所建议的那样,最好的解决方案是更改您的命名方案以避免全部大写:

          namespace FANLib {
            namespace Error {
              enum Type {
                /// FSL error codes
                FSL_Parser_File_IError, ...
          

          同样禁止:以 _ 或 __ 开头的标识符。 (它比这更复杂,但如果你避免所有以下划线开头的名字,你的生活会更简单。)

          【讨论】:

            【解决方案7】:

            如果您不使用 GDI,那么您可以定义 NOGDI 以禁止在 WinGDI.h 中定义宏。 Here 你可以找到其他有用的选项。

            【讨论】:

              【解决方案8】:

              以 E 和数字或 E 和大写字母开头的标识符应被视为保留,因为此类新宏可以添加到 <errno.h>

              【讨论】:

                猜你喜欢
                • 2013-12-11
                • 1970-01-01
                • 1970-01-01
                • 2013-04-12
                • 1970-01-01
                • 2014-07-01
                • 2010-09-20
                • 1970-01-01
                相关资源
                最近更新 更多