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;
}
a source to share
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.
a source to share
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.
a source to share
#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
a source to share