4

I have a custom c++ macro to emulate a foreach loop:

#define foreach(TYPE, ELEMENT, COLLECTION_TYPE, COLLECTION)\
for(COLLECTION_TYPE::iterator ELEMENT##__MACRO_TEMP_IT = COLLECTION.begin(); ELEMENT##__MACRO_TEMP_IT != COLLECTION.end(); ELEMENT##__MACRO_TEMP_IT++) \
{ TYPE ELEMENT = *(ELEMENT##__MACRO_TEMP_IT);

I know there are alternative ways to do a foreach loop - either by using C++11's, STL's, Qt's or Boost's foreach, but I was attempting a custom solution just for experience's sake.

The problem is, this macro requires either ending with 2 braces ("}}") or omit first brace and end with one, like this:

foreach(int, i, std::list<int>, indexes)
{
   //do stuff
}}

or

foreach(int, i, std::list<int>, indexes)

   //do stuff
}

I was wondering: is there a smart macro workaround to this, so one can use this macro as follows?

foreach(int, i, std::list<int>, indexes)
{
   //do stuff
}
Hydren
  • 363
  • 2
  • 11

1 Answers1

2
#define foreach(TYPE, ELEMENT, COLLECTION_TYPE, COLLECTION)\
for(COLLECTION_TYPE::iterator ELEMENT##MACRO_TEMP_IT = (COLLECTION).begin(); ELEMENT##MACRO_TEMP_IT != (COLLECTION).end(); ++ELEMENT##MACRO_TEMP_IT)\
for(bool ELEMENT##MACRO_B = true; ELEMENT##MACRO_B;)\
for(TYPE ELEMENT = *(ELEMENT##MACRO_TEMP_IT); ELEMENT##MACRO_B; ELEMENT##MACRO_B = false)

Test:

#include <iostream>
#include <list>

int main()
{
    std::list<int> indexes{1, 2, 3};

    foreach(int, i, std::list<int>, indexes)
    {
        std::cout << i << std::endl;
    }

    foreach(int, i, std::list<int>, indexes)
        std::cout << i << std::endl;

    std::list<std::list<int>> listOfLists{{1, 2}, {3, 4}};
    foreach(std::list<int>&, li, std::list<std::list<int>>, listOfLists)
        foreach(int, i, std::list<int>, li)
            std::cout << i << std::endl;
}

DEMO

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
  • 1
    Consider using `++ELEMENT##_MACRO_TEMP_IT` instead: http://stackoverflow.com/questions/24901/is-there-a-performance-difference-between-i-and-i-in-c – Beta Carotin Apr 29 '15 at 06:23
  • Would using reference on TYPE be more consise? Something like `for(TYPE& ELEMENT = ...` – Hydren Apr 30 '15 at 04:01
  • 1
    @Hydren letting the user to decide is much better, i.e. `foreach(int&, ...` – Piotr Skotnicki Apr 30 '15 at 05:47
  • I'm having a issue when the collection is `const`. This causes the `.begin()` function to return a `const_iterator`. Maybe a separate `const_foreach` version should solve the issue (replacing `::iterator` with `::const_iterator` in the macro). – Hydren Jul 15 '15 at 17:49