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

how to forward-declare std::set in c++?

提问人:Leon 提问时间:6/17/2020 最后编辑:Leon 更新时间:6/17/2020 访问量:875

问:

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

不能在以下代码中向前声明,而可以。std::setstd::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>& );
}

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

怎么做?

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

c++ 设置 std forward-declaration

评论

8赞 Sam Varshavchik 6/17/2020
尽管 C++ 标准指定了 的正式声明,但其他容器(如单个 C++ 实现)可以自由地遵循“假设”规则。例如,给定的 C++ 实现可以自由定义为别名:,以及其他此类内容。这通常是为了支持同一编译器的多个 ABI。总之,这种前向申报是无法便携的方式完成的。这是行不通的。std::setstd::vectorstd::vectortemplate<typename T, typename A> using vector=vectorv1<T,A>
1赞 NathanOliver 6/17/2020
您还犯了向命名空间 std 添加内容的犯规。您只能在 C++20 及更高版本中为自己的类型专用类模板。
0赞 Leon 6/17/2020
@NathanOliver谢谢,我不认为它污染了命名空间 std,因为它只是一个正向声明,不是吗?
0赞 Leon 6/17/2020
@SamVarshavchik 谢谢,我不确定我是否明白你的意思。你的意思是它不是一种便携式方式吗?即它可能适用于 GCC,但不适用于 VC++?
0赞 Sam Varshavchik 6/17/2020
这是正确的。

答:

2赞 JaMiT 6/17/2020 #1

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

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

一般来说,不要指望能够转发任何你无法控制的内容。即使它最初有效,它也有可能在库的任何升级/补丁时中断。


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

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