C ++在对象的向量上迭代,并将STL算法应用于成员变量 [英] C++ iterate over vector of objects and apply STL algorithms to member variables

查看:202
本文介绍了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 mean

  • no 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:

Run It Online

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>
>::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);
}

The result is a simple calling syntax which (bonus) allows for selecting any attribute, not only Foo::b.

Run It Online

// 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算法应用于成员变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆