Pot*_*ter 16 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;
};
Run Code Online (Sandbox Code Playgroud)
这往往起作用,因为容器没有按值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链接的文章中的破损示例相同.然而,虽然这篇文章似乎理所当然地认为"没有什么可以起作用",但解决方案对我来说似乎很简单 - std::map内部tree_node类应该是非成员模板,而不是成员非模板类.
无论如何,那篇文章很好地建立了设计意图,所以我想我的挑剔是关于"功能要求"的副标题只是那样.
Ker*_* SB 11
这是我尝试解释:
标准只是说你不能这样做,即使任何给定的具体实现可能没有问题支持这样的结构.但想象一下,例如,如果有人想要编写一个"小矢量"优化,通过该优化,矢量总是包含五个元素的空间.你有麻烦,因为你有自我指涉的类型.即使向量采用某种静态分支取决于值类型的大小,这也是一个问题.
因此,为了不包括这样的构造排除的实施,该标准只是说,你只能使用完整的类型.换句话说,大多数容器只包含对值类型的引用或指针的事实是实现细节而不是标准要求.
只是为了澄清这一点:如果你定义自己的类模板,完全有可能以明确支持不完整类型的方式设计它.标准的一个例子是std::unique_ptr,对不完整的类型参数T[](或甚至void)非常满意.
就我个人而言,我觉得 17.6.4.8/2 中实例化的措辞有点含糊,但根据 这篇文章,该标准的意图似乎不允许使用标准容器的递归数据类型。
class C { std::deque< C > x; };与此相关的是,VC2005在编译时
会发出 , 错误
class C { std::vector< C > x; };...
但是,在我的理解中,这种限制只是为了扩大标准容器实现的自由度。正如Kerrek SB提到的,可以存在允许递归数据结构的容器,并且
Boost.Container
似乎提供了这种设施。