有时,实例化具有不完整类型的标准容器以获取递归结构是有用的:
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;
};
这往往有效,因为容器没有value_type
类型的成员或者按值传递或返回任何value_type
个对象的成员函数。标准似乎并没有非常详细地说明不完整的模板参数,但在C ++11§17.6.4.8[lib.res.on.functions],“其他函数的要求”下有一点:
特别是,在以下情况下效果未定义:...如果在实例化模板组件时将不完整类型(3.9)用作模板参数,除非特别允许该组件。
这是否会使上述构造非法,即使实例化不在块范围内?这属于“用于实例化标准库模板组件的类型的操作”(也是17.6.4.8)吗?或者是一个库实现被禁止引发模板实例化,当所有特别需要的实例化成功时,这些实例化可能会因不完整类型而失败?
编辑:由于只有函数可以调用和实例化其他函数,因此将“对类型的操作...”限制为块范围内的操作似乎会将成员函数的内容保持为比内容更严格的要求签名和成员类定义。毕竟,在类型完成之前,使用multi_tree_node
做任何事情肯定没有意义。这扩展到显式支持不完整类型参数的std::unique_ptr
,即使在块范围中使用。
编辑2:为我提供正确的服务,因为我没有费心去测试trie_node
示例 - 我以前也尝过它。它与@Ise链接的the article中的破损示例相同。然而,虽然这篇文章似乎理所当然地认为“没有什么可以起作用”,但解决方案对我来说似乎很简单 - std::map
的内部tree_node
类应该是非成员模板,而不是成员非模板类。
无论如何,那篇文章很好地建立了设计意图,所以我想我的挑剔是关于“功能要求”的副标题只是那个。
答案 0 :(得分:11)
这是我尝试解释:
标准只是说你不能这样做,即使任何给定的具体实施可能没有支持这种结构的问题。但想象一下,例如,如果有人想要编写一个“小矢量”优化,通过该优化,矢量总是包含五个元素的空间。你有麻烦,因为你有自我指涉的类型。即使向量采用某种静态分支取决于值类型的大小,这也是一个问题。
因此,为了不排除包含此类构造的实现,标准只是说您必须只使用完整类型。换句话说,大多数容器只包含对值类型的引用或指针的事实是实现细节而不是标准要求。
只是为了澄清这一点:如果你定义自己的类模板,完全有可能以明确支持不完整类型的方式进行设计。标准中的一个示例是std::unique_ptr
,它对不完整的类型参数T[]
(甚至void
)非常满意。
答案 1 :(得分:4)
就个人而言,我觉得17.6.4.8/2中的实例化的措辞有点 暧昧,但根据 this article, 标准的意图似乎不允许使用递归数据类型 标准容器。
在相关的说明中,VC2005发出错误
class C { std::deque< C > x; };
,而它编译
class C { std::vector< C > x; };
...
但是,根据我的理解,这个限制只是为了扩大
自由执行标准容器。
因此,正如提到的 Kerrek SB ,可以有允许的容器
递归数据结构,和
Boost.Container
似乎提供了这种便利。
答案 2 :(得分:1)