[英]c++ how to create iterator over one field of a struct vector
我有一個所有原始類型的結構,如下所示:
struct record {
int field1;
double field2;
}
我有這個結構的實例向量,如下所示:
vector<record> records;
是否有可能/什么是創建將迭代field1
的vector<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'.
}
正如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.