在 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 中使用 QString
比 std::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
-------------------------------------
#undef
string
和 USINGQT
符号的正确位置在哪里?在头文件的末尾(这将需要在实现文件中重新定义和 "undefinition" )或仅在实现文件的末尾?
我也应该将 string
宏大写,难道我不应该...? >.>
如果我将宏定义 放在 命名空间中,我将收到大约。 800 条错误消息,其中包含 "no member of mySpace::std" 等条目。你能在没有进一步信息的情况下谈谈吗?否则它编译得很好。
编辑:我可能应该告诉你,我希望宏只适用于这个特定的头文件及其实现文件。尽管我当然会选择 typedef
s - 在宏情况下,我猜我应该将 #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
}
另请注意(如上所示),如果您只需要一个 布尔值 宏值,则无需将其设置为 1
或 0
, 只需使用 #ifdef
/#ifndef
.
在此之后,在您的 .cpp
中,只需使用 mySpace::string
,再也不用担心宏。
- 首先,您不需要通过使其等于 1 来切换
USINGQT
,您可以简单地 #define USINGQT
然后使用 #ifdef USINGQT
作为您的 if 语句。
- 就您切换使用哪个字符串库的能力而言,我建议使用 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
我正在编写一个 class(在头文件 myClass.h
和实现文件 myClass.cpp
中分开),我想将其与标准 C++ 和 Qt 框架一起使用。由于代码中的差异非常小(我想尝试一次),我决定 #define USINGQT 1
以便通过
#if USINGQT==1
//Qt code
#else
//standard code
#endif
现在我得出结论,当 "activating" [=] 时,在整个 class 中使用 QString
比 std::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
-------------------------------------
#undef
string
和USINGQT
符号的正确位置在哪里?在头文件的末尾(这将需要在实现文件中重新定义和 "undefinition" )或仅在实现文件的末尾?我也应该将
string
宏大写,难道我不应该...? >.>如果我将宏定义 放在 命名空间中,我将收到大约。 800 条错误消息,其中包含 "no member of mySpace::std" 等条目。你能在没有进一步信息的情况下谈谈吗?否则它编译得很好。
编辑:我可能应该告诉你,我希望宏只适用于这个特定的头文件及其实现文件。尽管我当然会选择 typedef
s - 在宏情况下,我猜我应该将 #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
}
另请注意(如上所示),如果您只需要一个 布尔值 宏值,则无需将其设置为 1
或 0
, 只需使用 #ifdef
/#ifndef
.
在此之后,在您的 .cpp
中,只需使用 mySpace::string
,再也不用担心宏。
- 首先,您不需要通过使其等于 1 来切换
USINGQT
,您可以简单地#define USINGQT
然后使用#ifdef USINGQT
作为您的 if 语句。 - 就您切换使用哪个字符串库的能力而言,我建议使用 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