Why won't this compile and how can it be implemented so that it gets executed?

Here is the C ++ code I'm playing with:

#include <iostream>
#include <vector>

#define IN ,
#define FOREACH(x,y) for(unsigned int i=0;i<y.size();i++) { x=y[i];
#define ENDFOREACH }

using namespace std;

int main()
{
    vector<int> ints;
    ints.push_back(3);
    ints.push_back(4);
    ints.push_back(5);
    ints.push_back(6);

    FOREACH(int item IN ints)
        cout << item;
    ENDFOREACH

    return 0;
}

      

However, I am getting the error:

the "FOREACH" macro requires 2 arguments, but only 1 given

The code compiles if I change IN

to comma. How can I replace IN

with a comma?

Update: For those interested, here is the final version, which, if I really say so, is pretty nice.

#include <iostream>
#include <vector>

#define in ,
#define as ,
#define FOREACH_(x,y,z) \
        y x; \
        if(z.size()) x = z[0]; \
        for(unsigned int i=0,item;i<z.size();i++,x=z[i])
#define foreach(x) FOREACH_(x)

using namespace std;

int main()
{
    vector<int> ints;
    ints.push_back(3);
    ints.push_back(4);
    ints.push_back(5);
    ints.push_back(6);

    foreach(item as int in ints)
    {
        cout << item << endl;
    }

    return 0;
}

      

+2


a source to share


6 answers


Others have already explained why it doesn't compile as is.

To do this, you have to give it a IN

chance to turn into a comma. To do this, you can introduce an extra level of "indirection" in the macro definition

#define IN , 
#define FOREACH_(x,y) for(unsigned int i=0;i<y.size();i++) { x=y[i]; 
#define FOREACH(x) FOREACH_(x)
#define ENDFOREACH } 

      

In this case, you will have to use a substitute for the comma (like yours IN

) and cannot explicitly specify the comma explicitly. That is, now it is



FOREACH(int item IN ints) 
    cout << item; 
ENDFOREACH 

      

compiles fine and

FOREACH(int item, ints) 
    cout << item; 
ENDFOREACH 

      

no.

+4


a source


The compiler does not expand the macro IN

before it reads the arguments FOREACH

. In fact, I think this is intentional (so you can pass the comma to the macro).

Unfortunately, you have to use FOREACH(int item, ints)

.



You can also #define IN

(do nothing) and then use FOREACH(int item, IN ints)

, which is not so nice but acceptable.

However, you can just use STL or Boost for foreach if you don't specifically want to create your own.

+3


a source


The extension for IN

in your example doesn't happen early enough, but you can pass the extended version to another macro:

#define FOREACH(x) DO_FOREACH(x)
#define DO_FOREACH(x,y) for( ... ) ...

      

+1


a source


#define IN ,
#define XFOREACH(x,y) for(unsigned int i=0;i<y.size();i++) { x=y[i];
#define FOREACH(x) XFOREACH(x)
#define ENDFOREACH }

      

As the previous posters noted, the preprocessor does not expand the macros in the arglist before breaking it down into an argument. However, as long as the macro doesn't use #

or ##

, it expands the macros in the arguments before replacing them in the macro body, so the extra indirect action does the trick

+1


a source


Check BOOST_FOREACH - it does what you want

http://www.boost.org/doc/libs/1_35_0/doc/html/foreach.html

0


a source


The preprocessor does not expand IN

to comma until it reads the arguments FOREACH

.

I'm pretty sure the C ++ preprocessor only has one pass, so you'll have to use:

FOREACH(int item, ints)
    cout << item;
ENDFOREACH

      

0


a source







All Articles