经常会遇到以下情况。(不失一般性:在下面的例子中,我使用最简单的两个容器情况,但在几何算法的实现中需要大量这样的容器来描述相互连接的图形数据结构。)
我有两种数据类型 A
和 B
的许多值相互引用(通常不是一对一的关系),例如通过(本机)指针或引用。它们都被放置在容器中,例如 using CA = std::container1< A >;
和 using CB = std::container2< B >;
。某个函数的结果是一对 CA
和 CB
实例。当我有了一个 CA
实例的元素时,我想要删除 CB
实例中引用的元素,反之亦然。
struct A;
struct B;
using CA = std::container1< A >;
using CB = std::container2< B >;
我想定义A
和B
如下:
struct A
{
int payload;
typename CB::iterator pb; // hard error here in general case of choosing `std:container2`
};
struct B
{
double payload;
typename CA::iterator pa;
};
// ...
PA a;
PB b;
// ...
assert(!a.empty());
assert(a.begin()->pb != b.end()); // and pb is not default-constructed
b.erase(a.begin()->pb);
但是在一般情况下,我无法声明typename CB :: iterator pb;
,只能声明B /*const*/ * pb;
或B /*const*/ & pb;
,因为类型B
是CB
声明的一部分,在使用容器CB
的成员typedef iterator
定义聚合体A
时,该类型是不完整的。
有一个提案是使用不完整类型的容器,但它目前还不是标准的一部分。
对于libstdc++和libc++中非调试版本的容器的当前实现,上述代码可能会因为偶然性而编译成功,但这并不是必须的。如果成功,迭代器的定义肯定不包含除了指向value_type
的指针或引用之外的任何内容。但是标准没有对此有要求。
正如您在实例中所看到的,对于std::unordered_set
,存在严重错误,因为其迭代器要求value_type
的std::hash
是完整类型。
由于架构(OOP)和性能原因,注释中提出的双重间接可能不是很好的解决方案。至少定义std::container3< B * >
以及std::container2< B >
并跟踪不同交叉引用容器的有效性看起来很丑陋。
迭代器本质上具有指针语义。它们不应要求所引用的类型是完整的。
如何在C++14
及之前解决这个问题?