有时,实例化具有不完整类型的标准容器以获取递归结构是有用的:
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类应该是非成员模板,而不是成员非模板类.
无论如何,那篇文章很好地建立了设计意图,所以我想我的挑剔是关于"功能要求"的副标题只是那样.
为什么 C++不允许实例化不完整类型的容器?
编写没有这个限制的容器当然是可能的 - boost :: container完全能够做到这一点.据我所知,它似乎没有给出任何性能或其他类型的增益,但标准声明它是未定义的行为.
例如,它确实阻止了构建递归数据结构.
为什么C++标准会强加这种任意限制呢?尽可能允许不完整类型作为模板参数的缺点是什么?
最近,当我在代码中更改了某些容器,分配器时,我遇到了很多typedef和不完整类型的问题.
我之前有过的
struct foo;//incomplete type.
typedef std::vector<foo> all_foos;
typedef all_foos::reference foo_ref;
Run Code Online (Sandbox Code Playgroud)
虽然不完全不确定上述行是否合法,但这适用于我使用的每个实现.当我以为我可以完成这项工作时std::tr1::array,改变了以上两行
typedef std::tr1::array<foo,5> all_foos;
typedef all_foos::reference foo_ref;
Run Code Online (Sandbox Code Playgroud)
这里的一切都中断了,因为编译器试图实例化array并且因为foo类型不完整而失败.我所需要的是foo对数组的"其他部分"的引用,而不是很感兴趣.当我创建这样的数组时,foo肯定会完全可用.
当typedef std::allocator<foo>::pointer foo_ptr被typedef替换时,同样的问题stack_alloc<foo,10>::pointer foo_ptr.其中,stack_alloc实现像
template<typename T,unsigned N>
struct stack_alloc
{
typedef T* pointer;
typedef std::tr1::aligned_storage<sizeof(T)*N, std::tr1::alignment_of<T>::value> buffer;
};
Run Code Online (Sandbox Code Playgroud)
假定该,value_type,pointer,reference,iterator等不依赖于的完整性T,以及明知类不能没有完全类型实例化,类型定义怎么这么能在独立于特定的容器或分配器的通用方式进行?
注意:
vector而不是替换它std::array,尽管问题仍然存在.stack_alloc 代码远未完成,只显示问题的一部分.all_foos不完整类型的对象foo.struct foo{ foo_ptr p;};无法定义.虽然可能 …