繁体   English   中英

c ++如何在结构向量的一个字段上创建迭代器

[英]c++ how to create iterator over one field of a struct vector

我有一个所有原始类型的结构,如下所示:

struct record {
    int field1;
    double field2;
}

我有这个结构的实例向量,如下所示:

vector<record> records;

是否有可能/什么是创建将迭代field1vector<int>::iterator的最佳方法? 如果我使用数组record records[n]怎么样? 我需要一些看起来像vector<int>::iterator

编辑:我需要的东西是vector<int>::iterator

制作迭代器适配器

首先,最简单的解决方案是迭代容器并从迭代器访问字段。

for (auto&& r : records) {
    int value = r.field1;
    /* do something with 'value' */
}

无论如何,如果你真的想要一个在解除引用时返回field1的迭代器,你可以很容易地实现一个从容器自己的迭代器派生的迭代器适配器。

struct my_it : public std::vector<record>::iterator {
    using std::vector<record>::iterator::iterator;
    int operator*() { return std::vector<record>::iterator::operator*().field1; }
};

并像这样使用它:

for (my_it it = std::begin(records); it != std::end(records); ++it) {
    int value = *it; // Dereferencing now returns 'field1'.
}

这是一个XY问题吗?

正如Ben Voigt的回答中所解释的那样,没有办法创建一个std::vector<int>::iterator ,它迭代除了存储在连续数组中的int元素之外的东西。

如果需要一个接受输入迭代器的函数,那么将它作为模板函数 这样,它将与任何容器类型的迭代器一起使用。 这就是标准库中所有算法的实现方式。

template <typename InputIt>
void func(InputIt first, InputIt last) {
    for (; first != last; ++first) {
        value = *it; // Dereferences input iterator of any type.
    }
}

迭代器应该通过它们的操作(即读取,递增,递减,随机访问)接口, 而不是它们的显式类型。 迭代器按其支持的操作数量进行分类。

例如,如果您需要迭代一个范围并在一次传递中读取所有值,那么您需要输入迭代器作为参数。 迭代器本身的类型应该是无关紧要的。

有关迭代器类别的更多信息,请参阅此处

你运气不好

vector<int>::iterator不是多态的1 没有地方可以进入并更改指针步长。 vector<int>::iterator迭代一系列连续的 int对象,并且不会连续存储int对象。

这就是为什么所有C ++标准算法都可以接受任何类型的迭代器。 如果使函数成为接受任意迭代器类型的模板,则可以像使用Snps编写的那样使用迭代器适配器。


1多态性相对于指针算法来说很 ,如果它没有与普通数组相似的性能,那么没有人会使用std::vector

您可以在原始vector上使用lambdas。

例如:

for_each(records.begin(), records.end(), [](record& foo){/*operate on foo.field1 here*/});

请注意,绝大多数其他算法也接受lambdas,因此您可以使用lambda迭代原始vector来访问field1

我在这里很冒昧,但你所寻找的行为似乎与map非常相似,所以你可能想看看它。

我想你可能会加入Boost和邪恶,你也可以用这个来拼凑一些东西: http//www.boost.org/doc/libs/1_57_0/libs/range/doc/html/range/reference/adaptors/reference /strided.html

好像你要求这样的东西

for(std::vector<record>::iterator i=records.begin(), end=records.end(); i!=end; ++i)
{
    std::cout << i->field1 << std::endl;
}

或者在C ++ 11中

for(auto i=records.begin(), end=records.end(); i!=end; ++i)
{
    std::cout << i->field1 << std::endl;
}

如果你真的想要一个成员迭代器,你可以这样做:

template <class M>
struct member_traits;

template <class T, class C>
struct member_traits<T C::*>
{
    using class_type = C;
    using return_type = T;
};

template <class Iterator, class C, class M>
struct member_iterator : Iterator
{
public:
    using Iterator::Iterator;

    template <class I, class Member>
    member_iterator(I&& begin, Member&& member)
        : std::vector<C>::iterator(std::forward<I>(begin))
        , member(std::forward<Member>(member))
    {
        static_assert(std::is_member_pointer<Member>::value,
                      "Member must be dereferenceable");
    }

    typename member_traits<M>::return_type& operator*()
    {
        return (*static_cast<Iterator&>(*this)).*member;
    }
private:
    M member;
};

template <class Member, class Iterator>
auto make_member_iterator(Member&& member, Iterator&& it)
    -> member_iterator<std::decay_t<Iterator>, typename member_traits<Member>::class_type, std::decay_t<Member>>
{
    return {std::forward<Iterator>(it), std::forward<Member>(member)};
}

struct Record
{
    int field1;
    double field2;
};

int main()
{
    std::vector<Record> v { {1, 1.0}, {2, 2.0}, {3, 3.0} };

    for (auto it = make_member_iterator(&Record::field1, v.begin()); it != v.end(); ++it)
    {
        std::cout << *it << " ";
    }
}

演示

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM