命名空间和宏定义之间的冲突问题

6

我有一个严重的问题。我有两个命名空间内的枚举如下:

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 error C2589:'constant':'::'右侧的非法标记

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

错误3 error C2039:'FSL_PARSER_FILE_IERROR':不是 '`global namespace'' 的成员

是否有什么方法可以解决这个问题,而无需由于一些没有考虑周全的 #define 而更改我的命名空间?我在另一篇帖子中读到可以 #undef ERROR,但那样安全吗?

8个回答

14

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

(顺带一提,<windows.h>#define了其他一些东西,比如GetPrinter,确实很恼人。我通常会使用#undef来取消定义。只在.cpp文件中包含<windows.h>并确保受头文件影响的范围尽可能小也有所帮助。)


你提出了几个非常好的观点。不幸的是,我仍然只能给你的答案投一票。 - sbi
2
我会补充一下,“标准接受的惯例”是所有大写字母的标识符都是宏。 - Martin York
5
Windows.h抛弃所有“通常被接受的约定”,并在宏定义中声明了许多内容。但是,遵循这个建议是好的。除了#define之外,不要在任何其他地方使用全大写字母,并且不要让Windows.h在您的头文件中可见。 - jalf

2

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


2
跟随“重命名你的命名空间”风潮,因为ERROR实在是太常见且不具备描述性。请找到更加具有描述性的名称。

1

我觉得如果你取消定义它,应该不会有问题。但是,你需要在使用枚举和windows.h的所有地方都这样做。最好的办法是重新命名你的命名空间。


1

您可能需要重构您的代码,以便 #include 只出现在必要的地方。"正确" 的方法甚至可能涉及制作单独的文件和头文件,包括您将从 windows.h 调用的函数的接口。

然而,如果您只想要一个简单的解决方法,并且关注于 #undef ERROR 导致的副作用,只需在声明完成后重新定义 ERROR:

#undef ERROR
namespace ERROR {
#define ERROR 0

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

话虽如此,如果您仅仅未定义 ERROR,那么应该没问题。它只会影响 C 预处理器从那一点开始处理 ERROR(或者说不处理 ERROR)。

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


不是一个好主意;微软在新的SDK版本中更改#define并不罕见。即使是常量(尽管ERROR可能不会受到影响),也会发生这种情况。 - MSalters
你说得对,这不是一个好的实践,假设标签的值总是一个给定的常量很容易导致难以调试的副作用。但是为了辩护自己,这不是我的第一个建议,也不是最后一个建议,我从来没有说过什么是好的修复方法,我只是说它是一个简单的修复方法(或快速修复方法)- 而这些类型的修复通常会导致难以调试的副作用! - lcv

0
最好的解决方案是更改您的命名方案,避免使用全大写字母,正如其他人所建议的那样:
namespace FANLib {
  namespace Error {
    enum Type {
      /// FSL error codes
      FSL_Parser_File_IError, ...

同样禁止使用以下标识符:以 _ 或 __ 开头的标识符。(实际情况比这更复杂,但如果您避免使用所有以下划线开头的名称,您的生活将更简单。)


0

如果您不使用GDI,则可以定义NOGDI以抑制在WinGDI.h中定义宏。在这里,您可以找到其他有用的选项。


0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接