Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ foreach loop with pointers instead of references

Tags:

c++

foreach

c++11

I have this Container class with begin() and end() functions for use with c++11 foreach loops:

class Element
{
    //content doesn't matter
};

class Container
{
    Element* elements;
    int size;

    /* constructor, destructor, operators, methods, etc.. */

    Element* begin() { return elements; };
    Element* end()   { return elements + size; };
};

This is now a valid c++11 foreach loop:

Container container;
for (Element& e : container)
{
    //do something
}

But now consider this foreach loop:

Container container;
for (Element* e : container)
{
    //do something
}

Is it possible to have a foreach loop with Element* instead of Element& like this?
This would also have the great advantage of preventing one from typing for (Element e : container) which would copy the element each time.

In that case begin() and end() would have to return Element** as far as I know.

But sizeof(Element) is not guaranteed to be sizeof(Element*) and in most cases they don't match. Incrementing a pointer increments by the base type size which is sizeof(Element) for incrementing Element* and sizeof(Element*) for incrementing Element**.

So the prefix operator++() will offset the pointer by a false value and things get crappy. Any ideas how to get this to work?

like image 607
bricklore Avatar asked Aug 26 '15 16:08

bricklore


1 Answers

I agree with LRiO that what you have right now is probably the best solution. It additionally lines up with how the standard containers operate, and taking the path of least surprise for your users is always the best path to take (barring compelling reasons to diverge).

That said, you can certainly get the behavior you want:

class Container
{
    // ...

    struct iterator {
        Element* e;

        // this is the important one
        Element* operator*() { return e; }

        // the rest are just boilerplate
        iterator& operator++() { ++e; return *this; }
        iterator operator++(int) {
            iterator tmp{e};
            ++*this;
            return tmp;
        }

        bool operator==(iterator rhs) const { return e == rhs.e; }
        bool operator!=(iterator rhs) const { return e != rhs.e; }
    };

    iterator begin() { return {elements}; };
    iterator end()   { return {elements + size}; };
};

You could consider inheriting from std::iterator to get the typedefs right, or using boost::iterator_facade. But this'll at least give you the functionality.

like image 157
Barry Avatar answered Oct 05 '22 22:10

Barry