本文介绍了C ++在对象的向量上迭代,并将STL算法应用于成员变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 struct Foo { std :: string a; double b = 1.0; }; int main() { std :: vector< Foo> fooVector(20); //遍历所有成员b - 就像我们迭代std :: vector< double> std :: discrete_distribution< int> dist(/ * ?? * /,/ * ?? * /); } 有了快速,我的意思是 没有自定义迭代器 - 或者只有一个非常轻量级的( - 几行代码,没有提升 iterator_facade 。), 不修改取消引用运算符( - 不快速)。 解决方案这里是我的注释中提到的解决方案: struct LightIterator:public std: :vector< Foo> :: iterator { LightIterator(std :: vector< Foo> :: iterator it):std :: vector< Foo> :: iterator(it){} 双& operator *(){return std :: vector< Foo> :: iterator :: operator *()。 } }; 您可以这样使用: std :: accumulate(LightIterator {fooVector.begin()}, LightIterator {fooVector.end 0.0); EDIT :@TartanLlama是关于与实际类型 std :: vector< Foo> :: iterator 。 为了获得更通用的解决方案,我建议你定义一个包装迭代器类,当 std :: vector< Foo> :: iterator 是一个原始指针。例如: (注意我现在允许选择任意属性) 模板< typename PointerType, typename ItemType, typename AttributeType > struct LightIterator_FromPointer:public std :: iterator< std :: input_iterator_tag, std :: remove_pointer_t< PointerType>> { PointerType it; AttributeType ItemType :: * pointerToAttribute; LightIterator_FromPointer(PointerType it_,AttributeType ItemType :: * pointerToAttribute_):it(it_),pointerToAttribute(pointerToAttribute_) {} AttributeType& operator *(){return it-> * pointerToAttribute; } AttributeType * operator->(){return it; } //输入迭代器样板:http://en.cppreference.com/w/cpp/concept/InputIterator 使用this_t = LightIterator_FromPointer< PointerType,ItemType,AttributeType> ;; // less typing ... LightIterator_FromPointer(const this_t& other):it(other.it){} bool operator!=(const this_t& other)const {return it!= other.it ; } this_t& operator ++(){++ it; return * this; } this_t operator ++(const int){return {it ++}; } }; 当 std ::仍然保留原来的最小向量< Foo> :: iterator 实际上是一个类: typename IteratorType, typename ItemType, typename AttributeType > struct LightIterator_FromClass:public IteratorType { AttributeType ItemType :: * pointerToAttribute; LightIterator_FromClass(IteratorType it_,AttributeType ItemType :: * pointerToAttribute_):IteratorType(it_),pointerToAttribute(pointerToAttribute_) {} AttributeType& operator *(){return IteratorType :: operator *()。* pointerToAttribute; } }; 最后,为了抽象应该在调用点使用的light迭代器类型的细节,您可以定义一个 make_iterator()函数来处理一切: template< typename IteratorType, typename ItemType, typename AttributeType > typename std :: conditional< std :: is_pointer< IteratorType> :: value, LightIterator_FromPointer< IteratorType,ItemType,AttributeType> ;, LightIterator_FromClass< IteratorType,ItemType,AttributeType> > :: type make_iterator(IteratorType it,AttributeType ItemType :: * pointerToAttribute) { return typename std :: conditional< std :: is_pointer< IteratorType> :: value, LightIterator_FromPointer< IteratorType,ItemType,AttributeType>, LightIterator_FromClass< IteratorType,ItemType,AttributeType> > :: type(it,pointerToAttribute); } 结果是一个简单的调用语法 em>允许选择任何属性,不仅 Foo :: b 。 //来自实际迭代器的light迭代器class { std :: vector< Foo> fooVector(20); double acc = std :: accumulate(make_iterator(fooVector.begin(),&Foo :: b), make_iterator(fooVector.end(),& Foo :: b ), 0.0); cout<< acc<< endl } //来自指针迭代器的轻迭代器 { std :: array< Foo,20> fooVector; double acc = std :: accumulate(make_iterator(fooVector.begin(),&Foo :: b), make_iterator(fooVector.end(),& Foo :: b ), 0.0); cout<< acc<< endl } What again is the quick way to iterate over a vector of custom objects but access only a single member in order to apply general STL-algorithms?struct Foo{ std::string a; double b = 1.0;};int main(){ std::vector<Foo> fooVector(20); // iterate over all members b -- as if we were iterating over a std::vector<double> std::discrete_distribution<int> dist(/*??*/, /*??*/);}With "quick" I meanno custom iterator -- or only a very lightweight one (--a few lines of code, no boost iterator_facade, etc.), no modification of the dereferencing operator (--not that quick). 解决方案 Here is the solution mentioned in my comment:struct LightIterator : public std::vector<Foo>::iterator{ LightIterator(std::vector<Foo>::iterator it) : std::vector<Foo>::iterator(it) {} double& operator*() { return std::vector<Foo>::iterator::operator*().b; }};Which you can use like this:std::accumulate(LightIterator{fooVector.begin()}, LightIterator{fooVector.end()}, 0.0);EDIT: @TartanLlama is right about the issue related to the actual type of std::vector<Foo>::iterator.As an attempt to have a more generic solution, I suggest that you define a wrapper iterator class for when std::vector<Foo>::iterator is a raw pointer. Something like:(notice that I'm now allowing arbitrary attributes to be selected. More on that later)template < typename PointerType, typename ItemType, typename AttributeType>struct LightIterator_FromPointer : public std::iterator<std::input_iterator_tag, std::remove_pointer_t<PointerType>>{ PointerType it; AttributeType ItemType::* pointerToAttribute; LightIterator_FromPointer(PointerType it_, AttributeType ItemType::* pointerToAttribute_) : it(it_) , pointerToAttribute(pointerToAttribute_) {} AttributeType& operator*() { return it->*pointerToAttribute; } AttributeType* operator->() { return it; } // input iterator boilerplate: http://en.cppreference.com/w/cpp/concept/InputIterator using this_t = LightIterator_FromPointer<PointerType, ItemType, AttributeType>; // less typing... LightIterator_FromPointer(const this_t& other) : it(other.it) {} bool operator!=(const this_t& other) const { return it != other.it; } this_t& operator++() { ++it; return *this; } this_t operator++(const int) { return {it++}; }};While still keeping the original "minimal" light iterator for when std::vector<Foo>::iterator is actually a class:template < typename IteratorType, typename ItemType, typename AttributeType>struct LightIterator_FromClass : public IteratorType{ AttributeType ItemType::* pointerToAttribute; LightIterator_FromClass(IteratorType it_, AttributeType ItemType::* pointerToAttribute_) : IteratorType(it_) , pointerToAttribute(pointerToAttribute_) {} AttributeType& operator*() { return IteratorType::operator*().*pointerToAttribute; }};Finally, in order to abstract the details of the light iterator type that should be used on the call site, you can define a make_iterator() function that takes care of everything:template < typename IteratorType, typename ItemType, typename AttributeType>typename std::conditional<std::is_pointer<IteratorType>::value, LightIterator_FromPointer<IteratorType, ItemType, AttributeType>, LightIterator_FromClass<IteratorType, ItemType, AttributeType>>::typemake_iterator(IteratorType it, AttributeType ItemType::* pointerToAttribute){ return typename std::conditional<std::is_pointer<IteratorType>::value, LightIterator_FromPointer<IteratorType, ItemType, AttributeType>, LightIterator_FromClass<IteratorType, ItemType, AttributeType> >::type(it, pointerToAttribute);}The result is a simple calling syntax which (bonus) allows for selecting any attribute, not only Foo::b.// light iterator from an actual iterator "class"{ std::vector<Foo> fooVector(20); double acc = std::accumulate(make_iterator(fooVector.begin(), &Foo::b), make_iterator(fooVector.end(), &Foo::b), 0.0); cout << acc << endl;}// light iterator from a "pointer" iterator{ std::array<Foo, 20> fooVector; double acc = std::accumulate(make_iterator(fooVector.begin(), &Foo::b), make_iterator(fooVector.end(), &Foo::b), 0.0); cout << acc << endl;} 这篇关于C ++在对象的向量上迭代,并将STL算法应用于成员变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
11-01 20:04