【问题标题】:Iterator adaptor that calls a member function when dereferenced取消引用时调用成员函数的迭代器适配器
【发布时间】:2017-04-13 05:27:30
【问题描述】:

我正在尝试编写一个迭代器适配器,它应该在每次取消引用时调用成员函数(或访问对象的成员)。以下是此类 API 的示例:

vector<pair<int,int>> ps = {{1,"a"}, {2,"b"}, {3,"c"}};

// Pairs that represent ranges
auto rf = make_adaptor(ps.begin(), ps.end(), [](const auto& x) {return x.first;}
auto rs = make_adaptor(ps.begin(), ps.end(), [](auto& x) {return x.second;}

应该打印出123:

for_each(rf.first, rf.second, [](const auto& x){std::cout << x;});

应设置ps 中对的每个second 元素:

for_each(rs.first, rs.second, [](auto& x){ x = "hello";});

我尝试编写自己的 iterator 类型和 make_adaptor 方法,但我似乎无法让它工作:

template <typename Iterator, typename UnaryOp>
struct adaptor {
    using value_type = std::result_of<UnaryOp(typename Iterator::reference)>::type;
    using reference = value_type&;
    using pointer = value_type*;
    using difference_type = typename Iterator::difference_type;
    using iterator_category = typename Iterator::iterator_category;

    adaptor(){};
    adaptor(Iterator it, UnaryOp func) : _it(it), _func(func) {}

    reference operator*() const { return _func(*_it); }
    pointer operator->() const { return &_func(*_it); }

    bool operator==(const adaptor& other) const { return _it == other._it; }
    bool operator!=(const adaptor& other) const { return _it != other._it; }

    adaptor& operator++() {
        ++_it;
        return *this;
    }

    Iterator _it;
    UnaryOp _func;
};



template <typename Iterator, typename UnaryOp>
    auto make_adaptor(Iterator first, Iterator last, UnaryOp func) {
        return std::make_pair(adaptor<Iterator, UnaryOp>(first, func),
                              adaptor<Iterator, UnaryOp>(last, func));
    };

原因如下:假设我有一个算法convex_hull,它适用于points。但现在我的对象包含points 作为成员(struct A { points pos;};)。我想在As 的集合上调用convex_hull

【问题讨论】:

  • 注意:operator-&gt; 是返回临时地址,operator* 是返回悬空引用。
  • 这是我想出的问题之一,不幸的是我不知道如何以通用的方式解决这些问题。
  • 我肯定会缓存函数调用的结果,因为您可能不想在每次迭代器被取消引用时计算func。然后您可以返回 cahced 变量(或它的地址)并注释,增加适配器会使它无效。
  • 这听起来很合理。我希望这将编译为与以下相同的机器代码:for(auto&amp; x : ps) {x.second ="hello";}。 (我不知道这是否可能,但它会非常棒)。因此,我认为引入额外的缓存逻辑会使编译器更难完成这项任务?

标签: c++ iterator adapter metaprogramming generic-programming


【解决方案1】:

使用range-v3,您可以执行类似的操作:

const std::vector<std::pair<int,const char*>> ps = {{1,"a"}, {2,"b"}, {3,"c"}};

for (const auto s : ps | ranges::view::keys)
{
    std::cout << " " << s;
}

for (const auto s : ps | ranges::view::transform([](const auto& p) { return p.first;} ))
{
    std::cout << " " << s;
}

Demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-05
    • 2021-01-01
    • 2020-03-10
    • 2017-07-17
    • 1970-01-01
    • 2015-01-13
    • 1970-01-01
    • 2011-05-02
    相关资源
    最近更新 更多