命名空间和定义之间的冲突

时间:2009-09-04 08:19:06

标签: c++ namespaces c-preprocessor

我有这个严重的问题。我在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:'常数':'::'

右侧的非法令牌      

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

     

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

我有什么办法可以解决这个问题,而不必因为一些不经意的#define而改变我的命名空间吗?我在另一篇文章中读过我可以#undef ERROR,但这有多安全?

8 个答案:

答案 0 :(得分:14)

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

(作为旁注,<windows.h> #define其他内容如GetPrinter,实际上它很烦人。我通常会使用#undef。这也有助于在.cpp文件中包含<windows.h>,并确保标题所影响的范围尽可能小。)

答案 1 :(得分:2)

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

答案 2 :(得分:2)

跳过“重命名你的命名空间”的潮流,只是因为ERROR过于普遍而且含糊不清。找一些更具描述性的东西。

答案 3 :(得分:1)

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

答案 4 :(得分:1)

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

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

#undef ERROR
namespace ERROR {
#define ERROR 0

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

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

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

答案 5 :(得分:0)

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

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

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

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