g2006
g2006

Reputation: 91

create iterator wrapper class for dereferencing pointers stored in a std container

using HT = std::map<int, int*>;

class ITERATOR_PROXY
{
public:
    ITERATOR_PROXY(HT& container) : m_container(container) { }

    auto begin() const  { return HT_ITERATOR_WRAPPER(std::begin(m_container)); }
    auto end() const    { return HT_ITERATOR_WRAPPER(std::end(m_container)); }

private:
    struct HT_ITERATOR_WRAPPER
    {
        HT_ITERATOR_WRAPPER(HT::const_iterator iter_) : iter(iter_) {}
        bool operator!=(const HT_ITERATOR_WRAPPER& other) const { return iter != other.iter; }
        auto& operator*()
        {
            //const int& key=iter->first;
            //int& val = *(iter->second);
            // how to return (key, val) which would allow possible modification? 
        }
        void operator++() {  ++iter; }
        HT::const_iterator iter;
    };

    HT& m_container;
};

int main()
{
    HT ht;
    std::array<int, 5> val = {0,1,2,3,4};

    for (int i = 0; i < 5; ++i) ht[i] = &val[i];

    ITERATOR_PROXY htw(ht);
    
    for(auto x : htw)
    {
        //should not be changing val's original values
        x.second += 100;
    }

    for(auto& x : htw)
    {
        // ok, changes the values in val array
        x.second += 100;
    }

    for(const auto& x : htw)
    {
        // I should expect a compile error in this case
        x.second += 100;
    }
}

I want to have some way of using range-based for loops with the map container, which changes the original value type from int* to int& inside the loop (expected use cases in main()).

I have been having some difficulty implementing the HT_ITERATOR_WRAPPER::operator*. What should it return in this case? My feeling is I need to store the dereferenced element somewhere and have operator* return a reference to it, but I am not sure how to make that work.

Edit: please note that I am looking to have operator * return references to both iter->firsts, and *(iter->second). This pair structure is in fact what *iter would return for associative containers.

Upvotes: 1

Views: 207

Answers (1)

Captain Hatteras
Captain Hatteras

Reputation: 519

It should return *iter;:

auto& operator*(){
    return *iter;
}

EDIT: If you want to dereference the underlying value, go with what @RemyLebeau said and do this:

int& operator*(){
    return *(iter->second); 
}

ANOTHER EDIT: If you want both values, then the best your going to get is this (NOTE: I have not tried this):

std::pair<int&, int&> operator*(){
    return std::make_pair<int&,int&>(iter->first, *iter->second); 
}

Upvotes: 1

Related Questions