【问题标题】:Is there a way to use a range-based iterator to iterate over references to the values of a list of pointers?有没有办法使用基于范围的迭代器来迭代对指针列表值的引用?
【发布时间】:2018-01-17 14:23:14
【问题描述】:

所以如果我有以下向量,其中有几个指向整数的指针:

std::vector<MyClass*> list;

我以后可以使用类似的方法对其进行迭代吗:

for (auto & (*item) : list)
{
    item.member = something;   //Goal is to require no dereferencing here
}

使用对列表内容值的引用比使用指向它们的指针更方便。

【问题讨论】:

  • 您可能可以编写和适配器,但我怀疑这会更糟
  • 你也可以看看boost pointer container library ...
  • 出于好奇。 item-&gt;member 有什么不好?
  • It would just be slightly more convenient to work with references to the list's contents' values than with pointers to them. 是迂腐的,从技术上讲,指针是列表内容的值。
  • @StoryTeller 我认为 OP 没有正确地提出问题。例如,当容器保存指向函子的指针时,它可能很有用。所以你不必写(*pitem)();

标签: c++ pointers reference iterator auto


【解决方案1】:

不,你不能。但是你为什么会呢?

for (auto pitem : list)
{
    auto& item = *pitem;
    item.member = something;   // no dereferencing here
}

除非你愿意编写乏味的代码,例如:

template<class TPointer>
class Adaptor
{
    struct Iterator
    {
        TPointer* _p;
        Iterator(TPointer* p) : _p(p) {}

        typename std::remove_pointer<TPointer>::type& operator*() { return **_p; }
        Iterator& operator++() { ++_p; return *this; }
        friend Iterator operator+(const Iterator& lhs, size_t s) { return lhs._p + s; }
        friend bool operator!=(const Iterator& lhs, const Iterator& rhs) { return lhs._p != rhs._p; }
    };

    std::vector<TPointer>& _v;
public:
    Adaptor(std::vector<TPointer>& v) : _v(v) {}
    Iterator begin() { return &_v[0]; }
    Iterator end()   { return begin() + _v.size(); }
};

只有这样你才能写:

struct SomeData { int n; } s1{2}, s2{4};
std::vector<SomeData*> data{&s1, &s2};

for (auto& item : Adaptor{data}) {
    std::cout << item.n << "\n";
}

live demo

【讨论】:

  • @slava 好吧,不是 for-range 循环所提供的语法糖。您需要编写自己的迭代器,或标准迭代器的适配器。但是,是的,“不能”并不是 100% 正确的。
  • "cannot" 可能不是 100% 正确,但“不能没有比这更多的代码”肯定是。
  • 如果有一个简单的语言特性可以做我想做的事,我宁愿了解它并利用它,也不愿忽略它并写更长的东西。如果没有,那么这不是一个巨大的损失。你的版本完全够用了。
  • @YSC 对,所以请改变你的措辞(你可以但效果不会更糟)
  • 问题更多在于问题的措辞。 “类似这样的事情”是主观的,根据对问题的解释,答案的当前措辞可能 100% 正确或更少。
【解决方案2】:

Boost 对此有一个范围适配器:http://www.boost.org/doc/libs/1_66_0/libs/range/doc/html/range/reference/adaptors/reference/indirected.html

for (auto& item : list | boost::adaptors::indirected) {
    // do whatever with your reference
}

另一种选择是迭代器适配器,在这种情况下更冗长:http://www.boost.org/doc/libs/1_66_0/libs/iterator/doc/indirect_iterator.html

auto beg = boost::make_indirect_iterator(std::begin(list));
auto end = boost::make_indirect_iterator(std::end(list));
for (auto& item : boost::make_iterator_range(beg, end)) {
    // do whatever with your reference
}

【讨论】:

  • 有什么 boost 没有解决方案吗?
【解决方案3】:

另一个使用嵌套 lambda 的变体。

std::for_each(std::begin(list), std::end(list), [] (auto p) {[item = *p] {
    item.member = something;
}();});

【讨论】:

  • @Snps 准确地说是以前的标准。 C++17 于 12 月发布。
猜你喜欢
  • 2015-08-27
  • 1970-01-01
  • 2021-11-17
  • 2019-09-19
  • 1970-01-01
  • 1970-01-01
  • 2013-07-08
  • 1970-01-01
  • 2011-06-01
相关资源
最近更新 更多