簡體   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