views:

230

answers:

4

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?

A: 

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?

Jorge Israel Peña
I'm aware it's not part of the language and I'm also aware there's a foreach in the STL and in Boost. However, the visual studio compiler supports foreach in the way I showed as a compiler extension, and I'd like to know how to make classes that work with it.
knuck
Ah okay, sorry for misunderstanding.
Jorge Israel Peña
Downvoted for misunderstanding, then apologizing for it? Turns out someone went on a downvoting spree.
Jorge Israel Peña
+10  A: 

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.

Pavel Minaev
can you give the simplest example of a class implementing those that will compile? Just need to know the methods' return types and whatever else I'm missing, because I'm not being able to compile with a simple class
knuck
You need to provide begin and end iterators.
GMan
Updated answer to include example. Actual return types do not matter, so long as they support all operations that are implied by described expansion of `for each`.
Pavel Minaev
@Pavel: Is this really an input iterator? Usually input iterators yield different values for consecutive `*it` invocations and their increment operations do nothing. That might not be a requirement, though, in which case this is indeed an input iterator. But in this case it is still an over-engineered one, since an input iterator wouldn't need the line member. Returning the result of `std::getline` (as an rvalue) from `*it` would suffice.
sbi
@sbi: you are correct in that incrementing in `operator*` is actually sufficient. However, this is not a requirement in and of itself - the ability to do so stems from the definition of `++` and `*` and their interactions for input iterators, and these can be satisfied in other ways. In any case, the question wasn't on iterators as such, but rather `for each`, so I went for code that is hopefully clearer in intent for a person who'd never written any kind of iterator before, even if not as tight as it should really be.
Pavel Minaev
@Pavel: Thanks for your explanations. (I had meant to add a note in my comment that I was just nitpicking, but forgot about it. Sorry for that.)
sbi
+1  A: 

use std::for_each

Davit Siradeghyan
+1 Prefer standards to non-standard extensions whenever possible.
Adrian McCarthy
`std::for_each` isn't really a replacement because it doesn't let you specify the block of code to execute for each iteration inline. In practice, I almost never see `std::for_each` used precisely for this reason - it's just easier to write a good old `for` loop with iterators. As for `for each` - it definitely doesn't have any place in portable code, but not all code is meaningfully portable anyway. If your application is already written using MFC or ATL, then you're stuck with VC++ anyway, and there's nothing wrong with using its language extensions either.
Pavel Minaev
Well, if portability isn't a requirement, I'd like throw lambda functions into the pool and vote this answer up. They are bound to be implemented by some compilers by now or pretty soon, and they will indeed make `std::for_each` the better solution, since they will become the standard that (hopefully) _all_ compilers eventually will support.
sbi
A: 

Your class should inherit IEnumerable to use foreach

PerlDev