使用STL容器前向声明对象

Forward declaration of objects with STL containers

本文关键字:声明 对象 STL 使用      更新时间:2023-10-16

考虑下面的代码片段,其中第一行仅用作前向声明

 class A;

之后定义新的类

class B
{
 vector<A> Av;  //line 1
 map<int, A> Am;  //line 2
 pair<int, A> Ap; //line 3
};

第1行和第2行似乎与前向声明(这可能告诉我那些容器使用指针类型的实现)有关,而第3行似乎无法在VS2012上编译。

我的问题是这种行为是由标准决定的,还是特定于我正在使用的编译器?

标准库类型的相关规则在[res.on.functions]:

特别地,在下列情况下的效果是未定义的:[…]如果在实例化模板组件时使用不完整类型(3.9)作为模板参数,除非该组件特别允许。

:

vector<A> Av;

很好。允许使用不完整类型实例化std::vector,只要它在使用任何成员之前变得完整即可。在[vector.overview]:

的标准中对此有一个显式的异常:

如果分配器满足分配器完整性,则在实例化vector时可以使用不完整类型T17.6.3.5.1需求。T应在产生的向量专门化的任何成员之前完成引用。

std::liststd::forward_list有类似的措辞。

:

map<int, A> Am;

是不规范的。std::map在实例化时需要一个完整的类型,如第一个引号所示。这个容器不像vector容器那样存在异常。

:

pair<int, A> Ap;

不可能工作,因为pair只是一个具有两个成员的简单结构体。为了拥有类型A的成员,您需要一个完整的类型。

[作为Barry回答的补充说明]

根据标准(c++ 17),实例化时只有std::vectorstd::liststd::forward_list可以使用不完全类型。

§23.3.11.1/3类模板向量概述[vector.overview]:

如果分配器满足分配器完整性要求,则在实例化vector时可以使用不完整类型T [allocator.requirements.completeness]。T应在引用vector的任何结果专门化成员之前完成。

§23.3.9.1/4类模板forward_list概述[forwardlist.overview]:

如果分配器满足分配器完整性要求,则在实例化forward_list时可以使用不完整类型TT必须在引用forward_list的任何成员之前完成。

§23.3.10.1/3类模板列表概述[list.overview]:

在实例化list时,如果分配器满足分配器完整性要求[allocator.requirements.completeness],则可以使用不完整类型TT应在引用list的任何成员之前完成。

不,这种行为是预期的和标准的。

理由是std::pair实际上形成了一个结构体,因此在实例化之前它的两个类型都必须是完整的。