是否可以在类定义中添加包含指令?



我目前正在做一个项目,我们有一组共享的头。现在我们想要添加一些私有字段,而不必将这些声明直接放在共享头文件中。

有人提出以下问题:

namespace something {
class Foo {
public:
Foo();
void doFoo();
private:
#if __has_include("foo_private.hpp")
#include "foo_private.hpp"
#endif
};
}

_private.hpp标头中,我们将为该类放置私有字段。当只有默认数据类型(int, bool等)时,这种方法可以正常工作。但是一旦你在_private.hpp文件中放入一个include,例如#include,一切都中断了。

它给出了以下错误expected unqualified-id before ‘namespace’,据我所知这是相当合乎逻辑的,因为你试图在类中定义一个命名空间。

示例_private.hpp文件

#ifndef DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#define DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#include <string>
int mySecretNumber;
std::string mySecretString;
#endif

现在我的问题是,有没有办法欺骗预处理器,或者以某种方式用不同的解决方案获得相同的结果?

namespace something {
class Foo {
public:
Foo();
void doFoo();
private:
#if __has_include("foo_private.hpp")
#include "foo_private.hpp"
#endif
};
}

如果该代码包含如下文件:

#ifndef DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#define DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#include <string>
int mySecretNumber;
std::string mySecretString;
#endif

然后你最终得到这个(尽管在现实中,#include本身将解析为<string>的内容,等等):

namespace something {
class Foo {
public:
Foo();
void doFoo();
private:
#ifndef DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#define DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#include <string>
int mySecretNumber;
std::string mySecretString;
#endif
};
}

也许这就是你的问题所在?你包括了"字符串"在类的中间,但它需要包含在文件的全局命名空间作用域中。

相反,在外部头文件的顶部包含string,不要在私有头文件中使用include保护,并且只将想要粘贴到类中的代码体放入该私有头文件中。出于这个原因,你可能不会称它为"。happy"。文件,但要明确它不是一个普通的头文件

此外,__has_include特性似乎是可疑的,因为如果你的私有头文件丢失,你可能不希望它编译成一个空类。

更糟的是,如果你编译了一个能找到头文件的翻译单元,然后又编译了另一个不能找到私有头文件的翻译单元,你最终会得到你的类的两个不同的定义,违反了一个定义规则——这是未定义的行为,不需要诊断。非常讨厌的东西(假设你的构建成功了)

我不是这种隐藏的大粉丝,因为它会使编辑器难以正确显示您的代码,为您的私有头着色和索引,或者以正常方式处理代码。您可以考虑使用PIMPL习惯用法,将类的实现隐藏在.cpp文件中,这样头文件的用户根本不必看到它。