X Macros, Is There a Compiler Flag or Something?

Hi, I was just playing with X Macros for some table generation consistency purposes, but I am running into some trouble with the pre-processing. I assume this is related to C++, but any help or suggestions would be appreciated.
This is test code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include<string>
#include <cstdlib>
#include<iostream>
#include<set>
using namespace std;
#include <stdio.h>
#define LIST_OF_KEYS\
X(key1)\
X(key2)\
X(key3)
class C_TestClass
{
public:

    set<long>setLong;
    set<string>setString;
    
#define X(a) typeOfKey##a,
    enum TypesOfKeys{LIST_OF_KEYS countOfTypesOfKeys};
#undef X
    
    C_TestClass():setLong(),setString()
    {
        cerr<<"constructing"<<endl;
#define X(a) setLong.insert(typeOfKey##a);cerr<<"setLong.insert(typeOfKey##a);"<<endl;    
    LIST_OF_KEYS;
#undef X
    
#define X(a) setString.insert(string("typeOfKey")+#a);
    LIST_OF_KEYS;
#undef X
    
    }
    void print()
    {
        cerr<<"printing"<<endl;
        cerr<<"setLong.size()="<<setLong.size()<<endl;
        for(auto val:setLong)
        {
            cerr<<"long = "<<val<<endl;
        }
        for(auto val:setString)
        {
            cerr<<"string = "<<val<<endl;
        }
    }
};
int main(void)
{
    C_TestClass test;
    cerr<<"print"<<endl;
    test.print();
}

This is what I expect the preprocessor to produce:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<string>
#include <cstdlib>
#include<iostream>
#include<set>
using namespace std;
#include <stdio.h>
class C_TestClass
{
public:

    set<long>setLong;
    set<string>setString;
    
    enum TypesOfKeys{typeOfKeykey1 , typeOfKeykey2 , typeOfKeykey3 , countOfTypesOfKeys};
    
    C_TestClass():setLong(),setString()
    {
        cerr<<"constructing"<<endl;
    setLong.insert( typeOfKeykey1 );cerr<<"setLong.insert(typeOfKey##a);"<<endl; setLong.insert( typeOfKeykey2 );cerr<<"setLong.insert(typeOfKey##a);"<<endl; setLong.insert( typeOfKeykey3 );cerr<<"setLong.insert(typeOfKey##a);"<<endl;;
    setString.insert(string("typeOfKey")+ "key1" ); setString.insert(string("typeOfKey")+ "key2" ); setString.insert(string("typeOfKey")+ "key3" );;
    
    }

    void print()
    {
        cerr<<"printing"<<endl;
        cerr<<"setLong.size()="<<setLong.size()<<endl;
        for(auto val:setLong)
        {
            cerr<<"long = "<<val<<endl;
        }
        for(auto val:setString)
        {
            cerr<<"string = "<<val<<endl;
        }
    }
};
int main(void)
{
    C_TestClass test;
    cerr<<"print"<<endl;
    test.print();
}

The actual result is fine if I compile what I expect to get out of the preprocessor:

constructing
print
printing
setLong.size()=0


But when I compile with g++, I get:

g++ -m64 -std-c++0x   -c -w -MMD -MP -MF build/Debug/GNU_J32-MacOSX/main.o.d -o build/Debug/GNU_J32-MacOSX/main.o main.cpp
main.cpp:19:34: error: missing ',' between enumerators
    enum TypesOfKeys{LIST_OF_KEYS countOfTypesOfKeys};
                                 ^
                                 , 


And then if I pretend to fix that (actually adding an extra comma), I then get this:

g++ -m64 --std=c++11   -c -w -MMD -MP -MF build/Debug/GNU_J32-MacOSX/main.o.d -o build/Debug/GNU_J32-MacOSX/main.o main.cpp

constructing
print
printing
setLong.size()=0

Can anyone help me understand what is going on and/or how to get the preprocessing I expect as if this was the old C? I'd prefer to preprocess C++ -c++11 code as if it was C99 if possible. I hope there are flags for this or something, but I'm at a loss for why such standard functionality isn't working for me. Any tips would be appreciated...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include<string>
#include <cstdlib>
#include<iostream>
#include<set>
using namespace std;
#include <stdio.h>

#define LIST_OF_KEYS \
	X(key1),\
	X(key2),\
	X(key3)

class C_TestClass
{
public:

    set<long>setLong;
    set<string>setString;
    
    enum TypesOfKeys
    {
		#define X(a) typeOfKey##a
			LIST_OF_KEYS,
			countOfTypesOfKeys
		#undef X
    };
	
    C_TestClass()
    {
        cout<<"constructing" << endl;
    
		#define X(a) setLong.insert(typeOfKey##a),\
			cout<<"setLong.insert(typeOfKey##a);"<<endl
			LIST_OF_KEYS;
		#undef X
    
		#define X(a) setString.insert(string("typeOfKey")+#a)
			LIST_OF_KEYS;
		#undef X
    }
    
    void print()
    {
        cout<<"printing"<<endl;
        cout<<"setLong.size()="<<setLong.size()<<endl;
        for(auto val:setLong)
        {
            cout<<"long = "<<val<<endl;
        }
        for(auto val:setString)
        {
            cout<<"string = "<<val<<endl;
        }
    }
};

int main(void)
{
    C_TestClass test;
    cout<<"print"<<endl;
    test.print();
}
Last edited on
X is expanded when you define LIST_OF_KEYS, not when you use it.
Last edited on
@L B, you mean where not when?
I mean when not where.
First of all, this works for me. However, I don't understand why it didn't work before.
This is what I think the new one expands to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include<string>
#include <cstdlib>
#include<iostream>
#include <stdio.h>
#include<set>
using namespace std;
#include <stdio.h>
class C_TestClass
{
public:

    set<long>setLong;
    set<string>setString;
    
    enum TypesOfKeys
    {
					typeOfKeykey1 , typeOfKeykey2 , typeOfKeykey3,
			countOfTypesOfKeys
		    };
	
    C_TestClass()
    {
        cout<<"constructing" << endl;
    
					setLong.insert( typeOfKeykey1 ), cout<<"setLong.insert(typeOfKey##a);"<<endl , setLong.insert( typeOfKeykey2 ), cout<<"setLong.insert(typeOfKey##a);"<<endl , setLong.insert( typeOfKeykey3 ), cout<<"setLong.insert(typeOfKey##a);"<<endl;
					setString.insert(string("typeOfKey")+ "key1" ) , setString.insert(string("typeOfKey")+ "key2" ) , setString.insert(string("typeOfKey")+ "key3" );
		    }
    void print()
    {
        cout<<"printing"<<endl;
        cout<<"setLong.size()="<<setLong.size()<<endl;
        for(auto val:setLong)
        {
            cout<<"long = "<<val<<endl;
        }
        for(auto val:setString)
        {
            cout<<"string = "<<val<<endl;
        }
    }
};
int main(void)
{
    C_TestClass test;
    cout<<"print"<<endl;
    test.print();
}

It seems to me that it's odd to use commas instead of semicolons to separate full lines of code. I don't know what the rule is if any on this topic though. I'm surprised to see that my impression of what this expands to works just fine. Why is it that my original attempt didn't work when it had semicolons where I would expect semicolons and that having commas where I expect semicolons somehow works? I'm thrilled that this works, but please help me understand it. Am I wrong about how these expand? I see that you are bringing time into this with the term "when." I'm not sure how to interpret that. I mean, if I assume time is to be interpreted as when that line of code with "#define LIST_OF_KEYS" in it is hit by the preprocessor, under the assumption that code is read left to right and then top to bottom like we read in English, then it seems there is no X in the data that will have hit the preprocessor yet at that time, so what does it mean to expand it at the time when it hasn't been encountered yet? I would have thought X was expanded when "#define X" was encountered... Anyway, could you maybe elaborate?
Thanks!
Last edited on
OMG, I found it:
I didn't have a space after LIST_OF_KEYS in it's definition:
1
2
3
4
#define LIST_OF_KEYS\
X(key1)\
X(key2)\
X(key3) 

should have been:
1
2
3
4
#define LIST_OF_KEYS \
X(key1)\
X(key2)\
X(key3) 
Topic archived. No new replies allowed.