stelonix
stelonix

Reputation: 756

How to write a class capable of foreach

It's been a while since Visual Studio added support for a foreach extension that works like

vector<int> v(3)
for each (int i in v) {
  printf("%d\n",i);
}

I want to know how to make any class able to use foreach. Do I need to implement some interface?

Upvotes: 5

Views: 652

Answers (4)

Davit Siradeghyan
Davit Siradeghyan

Reputation: 6323

You can use this

std::for_each

Upvotes: 1

Pavel Minaev
Pavel Minaev

Reputation: 101565

for each statement in VC++, when used on a non-managed class:

for each (T x in xs)
{
    ...
}

is just syntactic sugar for this:

for (auto iter = xs.begin(), end = xs.end(); iter != end; ++iter)
{
     T x = *iter;
}

Where auto means that type of variable is deduced automatically from type of initializer.

In other words, you need to provide begin() and end() methods on your class that would return begin and end input iterators for it.

Here is an example of class that wraps an istream and allows you to iterate over all lines in it:

#include <istream>
#include <iostream>
#include <fstream>
#include <string>


class lines
{
public:

    class line_iterator
    {
    public:

        line_iterator() : in(0)
        {
        }

        line_iterator(std::istream& in) : in(&in)
        {
            ++*this;
        }

        line_iterator& operator++ ()
        {
            getline(*in, line);
            return *this;
        }

        line_iterator operator++ (int)
        {
            line_iterator result = *this;
            ++*this;
            return result;
        }

        const std::string& operator* () const
        {
            return line;
        }

        const std::string& operator-> () const
        {
            return line;
        }

        friend bool operator== (const line_iterator& lhs, const line_iterator& rhs)
        {
            return (lhs.in == rhs.in) ||
                   (lhs.in == 0 && rhs.in->eof()) ||
                   (rhs.in == 0 && lhs.in->eof());
        }

        friend bool operator!= (const line_iterator& lhs, const line_iterator& rhs)
        {
            return !(lhs == rhs);
        }

    private:

        std::istream* const in;
        std::string line;
    };


    lines(std::istream& in) : in(in)
    {
    }

    line_iterator begin() const
    {
        return line_iterator(in);
    }

    line_iterator end() const
    {
        return line_iterator();
    }

private:

    std::istream& in;
};


int main()
{
    std::ifstream f(__FILE__);
    for each (std::string line in lines(f))
    {
        std::cout << line << std::endl;
    }
}

Note that implementation of line_iterator is actually somewhat bigger than the minimum needed by for each; however, it is the minimum implementation that conforms to input iterator requirements, and thus this class is also usable with all STL algorithms that work on input iterators, such as std::for_each, std::find etc.

Upvotes: 10

PerlDev
PerlDev

Reputation: 437

Your class should inherit IEnumerable to use foreach

Upvotes: -2

Jorge Israel Pe&#241;a
Jorge Israel Pe&#241;a

Reputation: 38586

foreach isn't part of the C++ language as far as I know. It's in C# though. Also, I think STL and/or Boost has a foreach method. Perhaps you're thinking about that one?

Upvotes: 0

Related Questions