简体   繁体   中英

Is there a way to use a range-based iterator to iterate over references to the values of a list of pointers?

So if I have the following vector with several pointers to ints in it:

std::vector<MyClass*> list;

Can I later iterate over it using something like:

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

It would just be slightly more convenient to work with references to the list's contents' values than with pointers to them.

No you cannot. But why would you?

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

Unless you're willing to write tedious code like:

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

Only then could you write:

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

Boost has a range adaptor for this: 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
}

Another alternative is iterator adaptors which are more verbose for this case: 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
}

Another variant using nested lambdas.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM