为了加快编译过程,我试图通过向前声明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::showSet
,所以我认为简化是有意义的。
怎么办?
提前谢谢,请原谅我糟糕的英语。
命名空间的目的之一是分离来自不同源的代码。这通常被认为是避免名称冲突,但它更深层次。
当库定义命名空间时,它(通常(声称完全拥有它。库保留更改命名空间中定义的所有内容的任何和所有方面的权利,通常仅保证公共 API。这延伸到前向声明。除非另有说明,否则命名空间中的任何前向声明都是库的域,因为库可能希望在后台更改内容。一些库认真对待这一点并提供前向声明标头,但如果没有这些,你就不走运了。
一般来说,不要期望能够转发声明任何您无法控制的内容。即使它最初可以工作,它也有可能在库的任何升级/补丁中中断。
转到std::set
,std
命名空间是为标准库保留的。标准库允许您在受限的情况下在std
命名空间中声明一些内容,但除此之外,它是禁止的。不幸的是,对于您的目标,标准库不需要前向声明标头。如果您希望代码在编译器升级后跨平台和/或稳定,则需要包含完整的标头。
切线:这是指定将自己的定义添加到namespace std
是未定义行为的基础。这并不是说这些东西能保证破坏某些东西,而是语言标准不能保证到底是什么会破坏东西。(实际上,如果你在namespace std
中定义一个名为supercalifragilisticiwillmisspellthis
的类,可能什么都不会爆炸。为了简单起见,应用了"未定义的行为"标签,并赋予了实现最大的自由度。