Search code examples
c++pointerscontainersautoranged-loops

Getting reference of dereferenced element from container of pointers by ranged loop


Given a container of pointers to ints, how can I increment the ints without using a dereference operator * within the loop body {}?

Here's the implementation with the dereference operator in the loop body:

#include <vector>
#include <iostream>
using namespace std;

int main() {
    int x = 0, y = 1, z = 2;

    auto increment_elements = [](vector<int*>& v) {
        for (auto& i : v) { ++*i };
    };

    increment_elements(vector<int*>{&x, &y, &z});

    cout << x << ", " << y << ", " << z << endl;
}

Replacing

for (auto& i : v) { ++*i };

with

for (int& i : v) { ++i };

gives MSVC-2013

error C2440: 'initializing' : cannot convert from 'int *' to 'int &'.

Why does replacement with

for (auto& i : v) { ++i };

compile but without incrementing the ints, and what is it doing?

I have the same question regarding replacement with

for (int*& i : v) ++i;

which gives the same result.


Solution

  • Given a container of pointers to ints, how can I increment the ints without using a dereference operator * within the loop body {}?

    Uses references over pointers whenever you can. You can't make vector of reference type so instead you can use a std::reference_wrapper<int>.

    std::vector<std::reference_wrapper<int>> v{x, y, z};
    

    increment_elements should probably also take a range to stay in line with generic programming. Then use get() on the elements and increment them:

    template<class Iter>
    void increment_elements(Iter first, Iter last)
    {
        for (; first != last; ++first->get(), ++first);
    }
    

    Then you can call it using begin() and end():

    increment_elements(std::begin(v), std::end(v));
    

    Or if you still want to take a vector as an argument, you can just iterate through and increment:

    for (int& i : v) ++i;
    

    and call it as:

    increment_elements(v);
    

    Why does replacement with [...] compile but without incrementing the ints, and what is it doing?

    auto deduces the element type as int* so decltype(i) becomes int*& which does the same thing as your last example.