如何在 C++ 中转发声明 std::set?



为了加快编译过程,我试图通过向前声明STL容器(如std::vector,std::set(来简化我的头文件MyClass.hpp

但是std::set不能在以下代码中向前声明,而std::vector可以。

namespace std {
template<typename T, typename A> class vector;
template<typename T, typename C, typename A> class set;
};
class MyClass_t {
void showVector( std::vector<int>& );
void showSet( std::set<int>& );
}

众所周知,标头非常长且复杂。如果我们将#include <set>添加到 MyClass.hpp 中,实际上每个使用 MyClass_t 的翻译单元都必须隐式包含标头。但我认为没有必要,因为不是每个使用 MyClass_t 的翻译单元都会调用MyClass_t::showSet,所以我认为简化是有意义的。

怎么办?

提前谢谢,请原谅我糟糕的英语。

命名空间的目的之一是分离来自不同源的代码。这通常被认为是避免名称冲突,但它更深层次。

当库定义命名空间时,它(通常(声称完全拥有它。库保留更改命名空间中定义的所有内容的任何和所有方面的权利,通常仅保证公共 API。这延伸到前向声明。除非另有说明,否则命名空间中的任何前向声明都是库的域,因为库可能希望在后台更改内容。一些库认真对待这一点并提供前向声明标头,但如果没有这些,你就不走运了。

一般来说,不要期望能够转发声明任何您无法控制的内容。即使它最初可以工作,它也有可能在库的任何升级/补丁中中断。


转到std::setstd命名空间是为标准库保留的。标准库允许您在受限的情况下在std命名空间中声明一些内容,但除此之外,它是禁止的。不幸的是,对于您的目标,标准库不需要前向声明标头。如果您希望代码在编译器升级后跨平台和/或稳定,则需要包含完整的标头。

切线:这是指定将自己的定义添加到namespace std是未定义行为的基础。这并不是说这些东西能保证破坏某些东西,而是语言标准不能保证到底是什么会破坏东西。(实际上,如果你在namespace std中定义一个名为supercalifragilisticiwillmisspellthis的类,可能什么都不会爆炸。为了简单起见,应用了"未定义的行为"标签,并赋予了实现最大的自由度。

最新更新