C++ 标准容器模板是否可以用不完整的类型实例化?
有时,实例化具有不完整类型的标准容器以获得递归结构非常有用:C++ 标准容器模板是否可以用不完整的类型实例化?,c++,templates,stl,incomplete-type,C++,Templates,Stl,Incomplete Type,有时,实例化具有不完整类型的标准容器以获得递归结构非常有用: struct multi_tree_node { // Does work in most implementations std::vector< multi_tree_node > child; }; struct trie_node { // Does not work in most implementations std::map< char, trie_node > next; }
struct multi_tree_node { // Does work in most implementations
std::vector< multi_tree_node > child;
};
struct trie_node { // Does not work in most implementations
std::map< char, trie_node > next;
};
struct multi_tree_node{//在大多数实现中都有效
std::vectorchild;
};
结构trie_节点{//在大多数实现中不起作用
std::mapnext;
};
这是因为容器没有类型为value\u类型
的成员,也没有按值传递或返回任何value\u类型
对象的成员函数。该标准似乎没有对不完整的模板参数做太多的说明,但在C++11§17.6.4.8[lib.res.on.functions]“其他函数的要求”中有一点:
特别是,在以下情况下,效果是未定义的:…如果在实例化模板组件时将不完整类型(3.9)用作模板参数,除非该组件特别允许
即使实例化不在块范围内,这是否会使上述构造非法?这是否属于“用于实例化标准库模板组件的类型上的操作”(也是17.6.4.8)?或者,当所有特定要求的实例化成功时,库实现是否禁止引发可能因不完整类型而失败的模板实例化
编辑:由于只有函数可以调用和实例化其他函数,因此将“类型上的操作…”限制在块范围内的操作似乎比签名和成员类定义的内容要求更严格。毕竟,在类型完成之前,对多树节点执行任何操作都毫无意义。这扩展到了std::unique_ptr
,它明确支持不完整的类型参数,即使在块范围中使用
edit2:我没有费心去测试trie_节点
示例,这对我来说是一件好事,我以前甚至试过。这与@Ise链接中的破损示例相同。然而,尽管这篇文章似乎想当然地认为“这样的方法是行不通的”,但解决方案对我来说似乎很简单-std::map
的内部tree\u节点
类应该是非成员模板,而不是成员非模板类
无论如何,那篇文章很好地确立了设计意图,所以我想我对“功能需求”这一副标题下的挑剔仅此而已。以下是我的解释:
标准只是说你不能这样做,即使任何特定的具体实现支持这样的构建可能没有问题。但是想象一下,例如,如果有人想写一个“小向量”优化,其中向量总是包含空间,比如说,五个元素。你马上就会遇到麻烦,因为你会有一个自我引用类型。即使向量根据值类型的大小采用某种静态分支,这也是一个问题
因此,为了不妨碍实现包含这样的构造,标准只是说您必须只使用完整类型。换句话说,大多数容器只包含对值类型的引用或指针这一事实是实现细节,而不是标准要求
只是为了澄清这一点:如果您定义了自己的类模板,那么完全有可能将其设计为显式支持不完整类型。标准中的一个例子是std::unique_ptr
,它对不完整的类型参数T[]
(甚至void
)非常满意。我个人觉得17.6.4.8/2中实例化的措辞有点夸张
模棱两可,但根据
,
该标准的意图似乎不允许使用递归数据类型
标准容器
在一个相关的注释中,VC2005为
类C{std::dequex;}代码>,当它编译时
类C{std::vectorx;}代码>…
不过,据我理解,这项限制只是为了扩大范围
自由实施标准容器。
正如Kerrek SB所提到的,可以有允许
递归数据结构,以及
似乎提供了此功能。一般来说,使用不完整类型作为标准库组件的模板参数是不正确的。以下是:
如果在实例化模板组件或评估概念时使用不完整的类型([basic.types])作为模板参数,除非该组件特别允许
请注意,自c++17以来,已向std::vector
授予显式权限,以允许不完整的类型。以下是:
如果分配器满足分配器完整性要求,则在实例化向量时可以使用不完整类型T。T应在引用向量的任何结果专门化成员之前完成
因此,在您的示例中,multi_tree_node
格式良好,但是trie_node
是UB。我在您发布的代码中没有看到任何不完整的类型?@JohnDibling:trie_node
在类自身范围内定义next
@JohnDibling时不完整。相关:顺便说一句,它是[17.4.3.6]
在C++03标准中,供感兴趣的人使用。另外,最好也添加段落所在的标记,在本例中,[lib.res.on.functions]
+1个很好的示例,但我将等待一些从头开始的标准解释…我的代码肯定违反了引用的要求,但问题的另一部分是需求是否或如何应用于函数/块范围之外。(因为只有函数可以调用和实例化其他函数,这似乎使成员函数的内容与签名的内容保持不同的标准