我经常面对以下情况。(在不失去通用性的情况下:我在下面的示例中使用了两个容器的最简单的情况,但在几何算法的实现中,需要大量的几何算法来描述相互关联的图形数据结构。)
我有两个数据类型( 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;
,因为作为CB
声明的一部分的B
类型在使用容器CB
的成员typedef iterator
定义聚合A
时是不完整的。
有一个不完整类型的容器的建议,但它目前并不是标准的一部分。
对于当前在libstdc++和libc++中实现非调试版本的容器,上面的代码可能会很好地编译,但这一点也不是强制性的。在成功的情况下,迭代器的定义不包含任何内容,只包含指针或对value_type
的引用。但在标准中没有这方面的要求。
正如您在实例化中看到的,std::unordered_set
存在严重错误,因为它的迭代器要求std::hash
of value_type
必须是完整类型。
由于体系结构(OOP)和性能方面的原因,双重间接提出的注释可能不是很好的解决方案。至少,定义std::container3< B * >
和std::container2< B >
以及跟踪不同交叉参照容器的动物园的有效性看起来很难看。
迭代器本质上具有指针语义。它们不应该要求引用类型的完整性。
如何处理C++14
和以前的问题?
发布于 2016-05-13 11:40:46
我用vector
、list
、deque
、set
和unordered_set
尝试了第二个例子。只有对于unordered_set
,我才得到一个编译器错误,可以通过使用指针容器来修复:
using CA = std::unordered_set< A* >;
using CB = std::unordered_set< B* >;
见这里 (Ideone.com C++14)。
发布于 2016-05-15 08:59:21
一个疯狂的解决方案是存储对齐存储,并手动管理迭代器的对象生存期,静态断言使存储达到合适的大小。
这是一个真正的痛苦和相当不安全(容易出错),但它的工作。
使用钻孔容器迭代器的大小/对齐方式。通过adl使用空闲函数访问迭代器。
std
倾向于过度要求完全定义的类型。
仔细使用crtp和标记可能会让您自动化危险的代码,但很棘手。
发布于 2016-05-13 17:27:02
在您的实际示例中,基本上您拥有的是:具有1:1关系的int
和double
,In存储在vector<int>
中,双字节存储在unordered_set<double>
中。
一种方法可能是简化问题,例如,您能够将数据放入unordered_map<double, int>
中吗?有时,这可能是真的,并将解决许多努力。有时,这可能不是真的,例如,您可能需要按ints对数据进行排序。
我认为使用std 2容器的路径充满了困难,编译错误只是冰山一角,例如:
另一个途径可以是:考虑使用类似boost、bimap或multi_index之类的东西。它们利用了这样一个事实:如果您希望两个基于节点的结构(例如两个集合)具有1:1的关系,那么对于insert,它只需要进行一个包含两个节点的分配。
https://stackoverflow.com/questions/37217251
复制