为什么 std::vector 适用于类定义中的不完整类型?
Why does std::vector work with incomplete types in class definitions?
出现了以下问题:
c++标准似乎说,std::vector
需要一个完整的类型才能工作。(见 https://en.cppreference.com/w/cpp/container/vector)那么,为什么下面的代码仍然编译呢?
#include <vector>
struct parent;
struct child
{
std::vector<parent> parents; //parent is incomplete here!
};
struct parent
{
std::vector<child> children;
};
这似乎有悖常理。如果std::vector
需要一个完整的类型,那么std::vector<parent>
不应该编译,因为在child
的类定义中只有它的前向声明是已知的。
- 这种行为是类定义的特殊之处吗?
- 我弄错了吗,
std::vector
不需要完整的类型? - 或者,这只是侥幸吗?从技术上讲,这是不允许的,但无论如何它适用于所有实现......
编辑
c++11 和 c++17 之间似乎有区别。我想了解 c++11 版本。
标准说(草案 N3690;这是 C++11 之后,C++14 之前):
[重新设置函数]
1 在某些情况下(替换函数、处理程序函数、 对用于实例化标准库模板的类型的操作 组件),C++标准库取决于 一个C++程序。如果这些组件不符合其要求,《标准》对实施没有要求。
2 具体而言,在以下情况下,效果是不确定的:
— 如果在以下情况下使用不完整的类型 (3.9) 作为模板参数 实例化模板组件,除非特别允许 该组件。
鉴于标准没有要求,并且效果是未定义的(据我所知,这与未定义的行为相同),因此对实例化"不起作用"的期望与期望它(似乎)"工作"一样。
自 C++17 起,要求放宽了,如果与适当的分配器一起使用,则std::vector
不需要完成值类型(默认分配器是合适的)。(这种自由并不延伸到使用所有成员函数;它们有额外的要求)。
标准报价(当前草案):
[矢量概述]
如果分配器满足分配器完整性要求,则在实例化向量时可以使用不完整类型 T。 在引用由此产生的载体特化的任何成员之前,T应是完整的。
[分配器.要求.完整性]
如果 X 是类型 T 的分配器类,则无论 T 是否为完整类型,X 都还满足分配器完整性要求:
- X 是一个完整的类型,并且
- 除value_type之外的所有成员类型的allocator_traits都是完整类型。
[默认分配器]
默认分配器的所有专用化都满足分配器完整性要求([分配器.要求.完整性])。
- 有没有一种方法可以通过"typedef"为重新定义的基本类型定义特征和强制转换运算符
- 强枚举类型定义:Clang Bug 还是 C++11 标准不确定性?
- 列表参数的类型定义
- 使用模板化的键类型定义 std::map,该键类型基于作为参数接收的函数
- 关于 C++ 中的函数类型定义
- C++(和 ROS) - 包含与前向声明引用,设置默认值和类型定义
- 将使用/类型定义限制为类范围
- 模板类型定义?
- C++:模板类的类型定义
- 如何对命名空间限定类型进行类型定义?
- 此递归模板类型定义是否有效C++?
- 具有调整对齐方式的类型定义
- C++从抽象类型定义类成员
- 用于C++代码的 API 监视器类型定义 (XML)
- 如何将result_of与函数类型定义一起使用
- 在C++的适当类型定义位置
- 如何根据模板类型定义浮点常量?
- 如何为缺少预定义运算符而不扩展命名空间"std"的标准类型定义运算符>> (istream &, ...)?
- 参数化类的别名(或类型定义)内部类
- 如果我想从类型"T"定义元素的容器(来自 STL),那么"T"必须使用默认构造函数?