[英]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.