将迭代器放在容器内部

putting iterator on a container inside it

本文关键字:内部 迭代器      更新时间:2023-10-16

我想写一个模板,得到一个容器模板作为参数(如vector, set, unordered_set)和一个类型T,并返回一个双重链接的容器,即容器的每个项目应包含一个三重:

  • a T
  • 一个prev迭代器,指向T的其他三元组
  • next迭代器指向T的其他三元组

内容如下:

template <template <class Tr> class Container, class T>
struct Triple {
  T value;
  typename Container< Triple<Container, T> >::iterator prev, next;
};
template <template <class Tr> class Container, class T>
using DoublyLinkedContainer = Container< Triple< Container, T> >;
#include <vector>
// default partial specialisation of the Allocator parameter
template <class T> using SimpleVector = std::vector<T>;
DoublyLinkedContainer<SimpleVector, int> v;

它似乎被编译器(gcc和clang)接受,但我不能理解如果我调用未定义的行为c++的递归类型定义是否可能,特别是我是否可以将vector在T的定义内?

编辑:以下是@Richard Hodges询问的一些背景:

我想在容器中存储一组对象的分区(在数学意义上),以便与该分区相关联的等价类是有序的。因此,我的想法是将这些等价类作为链表,因为它符合我对快速删除和顺序迭代的需求。当我开始使用这些等价类时,这个集合将被固定,这样就不会出现迭代器失效的问题。当然,比较、相等和哈希只依赖于三元组的T属性。

现在我不确定哪个容器更适合我的算法。因此,我正在尝试写这样一个模板来推迟选择。我可以在最后更改容器。

注意:如果我想要等效的向量,我也可以使用映射将两个迭代器关联到Tboost::flat_set,但这与这里提出的模板问题完全正交。

我认为这是你想要解决的问题的解决方案。

vec是Something对象的原始不可变向量(就像上面的T)。

weightedIndex是指向vec的交互器向量,在本例中,vec是通过Something.weight()升序排序的(但它可以是任何谓词)

#include <iostream>
#include <vector>
#include <algorithm>
struct Something
{
    Something(int weight)
    : _creationOrder { _createCount++ }
    , _weight { weight }
    {}
    int weight() const { return _weight; }
    std::ostream& write(std::ostream& os) const {
        os << "Something { createOrder=" 
        << _creationOrder 
        << ", weight=" << _weight << "}";
        return os;
    }
private:
    int _creationOrder;
    int _weight;
    static int _createCount;
};
std::ostream& operator<<(std::ostream& os, const Something& st) {
    return st.write(os);
}
int Something::_createCount { 0 };
using namespace std;
int main()
{
    vector<Something> vec { 10, 23, 76, 12, 98, 11, 34 };
    cout << "original list:";
    for(const auto& item : vec) {
        cout << "n" << item;
    }
    using iter = decltype(vec)::const_iterator;
    vector<iter> weightIndex;
    weightIndex.reserve(vec.size());
    for(auto i = vec.begin() ; i != vec.end() ; ++i) {
        weightIndex.push_back(i);
    }
    sort(weightIndex.begin(), weightIndex.end() , [](const iter& i1, const iter& i2) {
       return i1->weight() < i2->weight(); 
    });
    // weightIndex is now a vector of pointers to the Something elements, but the pointers
    // are ordered by weight of each Something
    cout << "nSorted index:";
    for(const auto p : weightIndex) {
        cout << "n" << *p;
    }
    cout << endl;
    // find the mid-weight
    auto ii = next(weightIndex.begin(), 3);
    // next one in list is
    auto next_ii = next(ii, 1);
    // find previous in weighted order
    auto prev_ii = prev(ii, 1);
    cout << "Selection:n";
    cout << "Current = " << **ii << endl;
    cout << "Next = " << **next_ii << endl;
    cout << "Previous = " << **prev_ii << endl;

   return 0;
}
输出:

original list:
Something { createOrder=0, weight=10}
Something { createOrder=1, weight=23}
Something { createOrder=2, weight=76}
Something { createOrder=3, weight=12}
Something { createOrder=4, weight=98}
Something { createOrder=5, weight=11}
Something { createOrder=6, weight=34}
Sorted index:
Something { createOrder=0, weight=10}
Something { createOrder=5, weight=11}
Something { createOrder=3, weight=12}
Something { createOrder=1, weight=23}
Something { createOrder=6, weight=34}
Something { createOrder=2, weight=76}
Something { createOrder=4, weight=98}
Selection:
Current = Something { createOrder=1, weight=23}
Next = Something { createOrder=6, weight=34}
Previous = Something { createOrder=3, weight=12}