Can I get the index of an item from within a range based for loop?

c++, c++11, indexing, loops, range

Solution

I came up with a solution — or rather an experimental solution. Here is how you will end up using it:

for(auto item : make_indexable(v))
{
      //std::get<0>(item) is the index
      //std::get<1>(item) is the object
}

And here goes the minimal implementation (it is just to demonstrate the basic idea):

#include <tuple>
#include <functional>

template<typename C>
struct indexed_container
{
    struct indexed_iterator
    {
        typedef typename C::value_type value_type;
        typedef std::tuple<size_t, std::reference_wrapper<value_type>> tuple_type;

        typename C::iterator _it;
        size_t _index;

        indexed_iterator(typename C::iterator it) : _it(it), _index(0) {}

        indexed_iterator& operator++()
        {
            ++_it;
            ++_index;
            return *this;
        }
        bool operator == (indexed_iterator const & other)
        {
            return _it == other._it;
        }
        bool operator != (indexed_iterator const & other)
        {
            return _it != other._it;
        }
        tuple_type operator*()
        {
            return std::make_tuple(_index, std::ref(*_it));
        }
    };

    indexed_container(C & c) : _c(c) {}

    indexed_iterator begin()
    {
        return indexed_iterator(_c.begin());
    }
    indexed_iterator end()
    {
        return indexed_iterator(_c.end());
    }
private:
    C & _c;
};

template<typename C>
auto make_indexable(C & c) -> indexed_container<C>
{
    return indexed_container<C>(c); 
}

Test code:

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{1,2,3};
    for(auto item : make_indexable(v))
    {
        std::cout << std::get<0>(item) << " => " << std::get<1>(item) << std::endl;

        std::get<1>(item) *= 10; //modify value!
    }
    std::cout << "\nModified\n";
    for(auto item : make_indexable(v))
    {
        std::cout << std::get<0>(item) << " => " << std::get<1>(item) << std::endl;
    }
}

Output:

0 => 1
1 => 2
2 => 3

Modified
0 => 10
1 => 20
2 => 30

Online demo

Note that this solution is not perfect, as it will not work with temporaries and const containers (and containers of const objects). Also, right now the underlying object will be returned as reference even if you write `auto item` as opposed to `auto & item` (in fact, you cannot write `auto &item`). But I think these issues can be fixed with a bit more effort and careful design. After all, it is just a demonstration of the basic idea.

Problem

I have defined a deque of pointers like this: ``` std::deque<BoardSquare *> mydeque; ``` I would like to use range based for loops with my deque: ``` for (BoardSquare * b : mydeque) { // do something involving the index of b } ``` Is it possible to get the index of an item from within a range based for loop?

Original source