在 C++ headers/implementation 文件中正确放置 #undef 指令

Correct to place an #undef directive in C++ headers/implementation files

我正在编写一个 class(在头文件 myClass.h 和实现文件 myClass.cpp 中分开),我想将其与标准 C++ 和 Qt 框架一起使用。由于代码中的差异非常小(我想尝试一次),我决定 #define USINGQT 1 以便通过

切换小部分代码
#if USINGQT==1
    //Qt code
#else
    //standard code
#endif

现在我得出结论,当 "activating" [=] 时,在整个 class 中使用 QStringstd::string 更方便19=] 开关。但是,上述方法会使代码变得非常混乱。我的解决方案(在头文件中):

#if USINGQT==1
    #include <QString>
    #define string QString
#else
    #include <string>
    #define string std::string
#endif

现在回答问题:

考虑文件看起来像

---myclass.h-------------------------
#ifndef MYCLASS_H
#define MYCLASS_H

#define USINGQT 1  //1=on, else off
#if USINGQT==1
    #include <QString>
    #define string QString
#else
    #include <string>
    #define string std::string
#endif

namespace mySpace {

class MyClass {
    string qtOrStd;
    string foo();
    //etc...
};

} //namespace
#endif //MYCLASS_H
-------------------------------------

---myclass.cpp-----------------------
#include "myclass.h"
using namespace mySpace;

//implementations
string MyClass::foo()   //string symbol occurs, as does the USINGQT
-------------------------------------
  1. #undef stringUSINGQT 符号的正确位置在哪里?在头文件的末尾(这将需要在实现文件中重新定义和 "undefinition" )或仅在实现文件的末尾?

  2. 我也应该将 string 宏大写,难道我不应该...? >.>

  3. 如果我将宏定义 放在 命名空间中,我将收到大约。 800 条错误消息,其中包含 "no member of mySpace::std" 等条目。你能在没有进一步信息的情况下谈谈吗?否则它编译得很好。


编辑:我可能应该告诉你,我希望宏只适用于这个特定的头文件及其实现文件。尽管我当然会选择 typedefs - 在宏情况下,我猜我应该将 #undef 放在实现文件的末尾。因为包含保护,宏不会被重新定义。

没有 #undef 宏,除非另一个文件试图 re-define 它。你不能 #undef 一个宏 在你用完它之前 因此,如果你 #define 一个 header 中的宏并且想要在包含 header 的文件中使用它,那么你不能在 header.

#undef

1) Where is the correct place to #undef the string and USINGQT symbols? At the end of the header file ...

只有 如果你在 header... 46=]没有.

or just at the end of the implementation file?

在实现文件末尾取消定义宏是没有意义的,因为在宏应用的文件末尾之后将不再有代码。让它保持定义。

2) I should capitalize the string macro as well, shoudln't I...? >.>

您不必将宏大写,但这是约定俗成的。也就是说,定义一个与标准 class 同名的宏只是自找麻烦。您应该在此处使用 typedef 而不是宏,以便在名称冲突的情况下获得有意义的错误消息。并使用另一个名称,如 string_t 或在命名空间中定义 typedef

3) If I put the macro definitions inside the namespace I receive approx. 800 error messages

错误不是来自在命名空间内定义宏。错误来自使用宏 as-if 它们是命名空间的一部分。例如,如果您说:

namespace mySpace {
#define string std::string
}
mySpace::string s;

然后 string 将被替换为 std::string 并且类型名称变为 mySpace::std::string。由于您没有在 mySpace 中定义 std 名称空间,这是错误的。您需要了解的是,名称空间对预处理器宏没有任何影响。这使得避免名称冲突变得更加困难,这也是您通常希望避免使用 pre-processor 宏的原因之一。

如果 USINGQT 宏适用于 所有 代码,因此所有文件都必须相同,您可能不想在 header,而是将其作为参数传递给编译器。这样您就可以轻松地使用不同的值进行编译而无需更改文件。


关于您的编辑:

即使你想在另一个文件中以不同的方式定义宏,在实现结束时取消定义它也没有效果,因为实现文件不会被包含 header.您应该避免需要多个 不同 宏定义(或缺少定义)的情况,但是如果您处于这种情况,那么是的,您唯一的解决方案是定义它分别在每个需要它的文件中,然后在任何需要它的 header 末尾取消定义。但是您不会遇到这种情况,因为您可以改用类型别名。

我看不出有任何理由要 #undef 这个宏。您肯定希望 all 您的代码在该宏的 one 状态下编译?那么你就不需要#undef了。

但是,我也强烈建议您使用 typedef 作为您的 string 定义。这样反正就更清楚了,你不会想着把它大写,甚至可以放到你的命名空间里。如果需要访问全局命名空间,请使用 ::

#define USINGQT
#ifdef USINGQT
    #include <QString>
#else
    #include <string>
#endif

namespace mySpace {
    #ifdef USINGQT
    typedef ::QString string;
    #else
    typedef ::std::string string;
    #endif
}

另请注意(如上所示),如果您只需要一个 布尔值 宏值,则无需将其设置为 10, 只需使用 #ifdef/#ifndef.

在此之后,在您的 .cpp 中,只需使用 mySpace::string,再也不用担心宏。

  1. 首先,您不需要通过使其等于 1 来切换 USINGQT,您可以简单地 #define USINGQT 然后使用 #ifdef USINGQT 作为您的 if 语句。
  2. 就您切换使用哪个字符串库的能力而言,我建议使用 typedef 和预处理器 if 语句。这将避免任何名称空间问题。下面显示了一个示例。

// ------------ 一些配置文件 ------------=

#define USINGQT

// -------------- MyClass.h --------------------=
// Header guard
#ifndef MyClass
#define MyClass 

// Conditional Header types
#ifdef USINGQT
// QT OPTION
typedef QString my_string;

#else
//  Not QT
typedef std::string my_string;
#endif

class MyClass {
public:
    my_string some_string;

    MyClass()
    {
        my_string = "hello world";
    }
};
#endif