【问题标题】:How can I make an iterator over fields of container's items?如何在容器项目的字段上创建迭代器?
【发布时间】:2016-04-24 13:57:36
【问题描述】:

比如说,我有一个类,里面有std::list<std::pair<int, std::string>>;我怎样才能为这个类实现一个迭代器,以便它迭代这个列表中包含的字符串?

或者,例如,在我的班级中,我有一个structs 的向量,其中包含abc 字段;我可以创建一个迭代器(可能继承vector的迭代器?不知道),它在取消引用时会返回一个std::pair,对应于(b, c)

我所说的迭代器是指类似于std::vector 的迭代器:我可以通过whatever.begin() 获取并迭代(如上所述)列表中的字符串。

UPD 好的,这里有更多关于我想要的信息。在我的HashMap 类中,我有itemsstructs 的列表:每个都有一个键、一个值和一个指向它在表中位置的指针。我需要的是一个迭代器;但不是我可以通过items.begin() 获得的那个,因为这个迭代器在取消引用时将返回我的结构。我需要一个迭代器,这样当用户调用HashMap.begin() 时我可以返回它,并且它应该取消引用到一个std::pair,对应于(键,值)。

希望这能让我的问题更清楚。

UPD2 这是我的struct,如果有帮助的话:

template<class KeyType, class ValueType>
struct node {
    KeyType key;
    ValueType value;
    node** place;

    node(KeyType key_ = KeyType(), ValueType value_ = ValueType()): key(key_), value(value_) {};
};

【问题讨论】:

  • 您不能使用任意结构定义。这将需要运行时反射,这在 c++ 中不可用。您可以为每个需要使用它的具体结构提供自己的迭代器实现。可能是std::tie() 在这样做时很有用。
  • 您要遍历列表中的字符串还是其他内容?
  • 您应该解释为什么您需要这样的迭代器,因为可能有其他方法可以做到这一点。
  • @Galik 准确地说,是的
  • 但是您仍然可以使用列表迭代器访问列表中的std::string 实例并执行操作it-&gt;second,除非我完全误解了这个问题

标签: c++ c++11 struct iterator


【解决方案1】:

一种优雅的方法是使用转换迭代器或转换范围:

#include <iostream>
#include <list>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/iterator/transform_iterator.hpp>

int main() {
    std::list<std::pair<int, std::string>> l;
    auto extractor = [](auto&& elem) { return elem.second; };

    // Using a transformed range.
    for(auto&& v: l | boost::adaptors::transformed(extractor))
        std::cout << v << '\n';

    // Using transform iterators.
    for(auto i = boost::make_transform_iterator(l.begin(), extractor), j = boost::make_transform_iterator(l.end(), extractor); i != j; ++i)
        std::cout << *i << '\n';
}

要为您的容器使用转换迭代器,您可以执行以下操作:

struct MyContianer
{
    std::list<std::pair<int, std::string>> container;

    static auto constexpr first_extractor = [](auto&& elem) { return elem.second; };
    using iterator_first = decltype(boost::make_transform_iterator(container.begin(), first_extractor));
    iterator_first begin_first() { return {container.begin(), first_extractor}; }
    iterator_first end_first() { return {container.end(), first_extractor}; }

    static auto constexpr second_extractor = [](auto&& elem) { return elem.second; };
    using iterator_second = decltype(boost::make_transform_iterator(container.begin(), second_extractor));
    iterator_second begin_second() { return {container.begin(), second_extractor}; }
    iterator_second end_second() { return {container.end(), second_extractor}; }

};
decltype(MyContianer::first_extractor) constexpr MyContianer::first_extractor;
decltype(MyContianer::second_extractor) constexpr MyContianer::second_extractor;

int main() {
    MyContianer c;
    c.begin_first();
    c.begin_second();
}

【讨论】:

  • 好吧,我很确定我不允许使用 boost 之类的,所以......虽然这很好,但这对我没有帮助
  • @Akiiino 如果你不能复用boost,你可以复用底层思想:为你的容器制作一个迭代器类模板,一个模板参数是转换函数/提取器对象类型。
猜你喜欢
  • 1970-01-01
  • 2015-02-03
  • 2019-06-06
  • 1970-01-01
  • 2018-05-20
  • 2018-10-12
  • 1970-01-01
  • 1970-01-01
  • 2012-08-03
相关资源
最近更新 更多