[Solved] C++ Macro question...

Started by
11 comments, last by ZealousEngine 15 years, 8 months ago
There are many times where I find myself writing dozens of lines of code where there is only a minor difference from line to line (a name for example). A good example is my function map. I have a list of component names, and I want to map each unique name to a unique function (since its faster than a big switch statement)...
Quote: mFuncMap[meshId] = &funcMesh mFuncMap[particleEffectId] = &funcParticleEffect mFuncMap[rigidBodyId] = &funcRigidBody
In the above case each unique component (mesh, particle effect, ect..) maps to a unique function. But it really bugs me that I have to write all this out long hand, when there SHOULD be a way to create some kind of loop...
Quote: for ( int i = 0; i < numComponents; ++i ) { mFuncMap[getComId(i)] = &func'MACRO_getComName(i)'; }
Is there anyway to do the above? Thanks! [Edited by - ZealousEngine on August 17, 2008 11:38:15 PM]
Advertisement
You could use boost::preprocessor to create a list of names and then expand the assignment for each id. Though in this case I'm not sure how much that would gain you over just using an array to initialize your map.
Hrmm I skimmed over boost::preprocessor, never used it before.. Could you please give an example showing how my above code could work with boost::preprocessor?

Here is another example of where I want to 'macro-ize' things.

One of my functions converts a typeId (integer) to a name (string). When I initialize the map, I have to do...

Quote:

mIdToStringMap[0] = "Mesh";
mIdToStringMap[1] = "ParticleEffect";
...

std::string toString( int id ) { return mIdToStringMap[id]; }



Now my whole point is - wouldnt it be nice if I could generate ONE list of 'names' (in macro form, or whatever), then use that ONE list to save me from having to write 40+ lines every time I do some kind of mapping like this. The only thing that really changes from line to line is the name, so how could I write a loop like the following...

Quote:
for ( int i = 0; i < numComponents; ++i ) {
//I want to REUSE the same MACRO_getComName() from the earlier function map example
mIdToStringMap = 'MACRO_getComName(i)';
}
For your second example, an alternative would be to read the integer-string pairs from a file. Also, in both cases you could clean up the code a bit by using the Boost Assignment library:
myFuncMap = boost::assign::map_list_of    ( meshId,           &funcMesh           )    ( particleEffectId, &funcParticleEffect )    ( rigidBodyId,      &funcRigidBody      );
Quote:
myFuncMap = boost::assign::map_list_of
( meshId, &funcMesh )
( particleEffectId, &funcParticleEffect )
( rigidBodyId, &funcRigidBody );


Yes but the whole point is I have MULTIPLE maps like this, and I dont want to have to write them out more than once. I just want to create ONE list of unique names, and somehow use that.
Take a look at the BOOST_PP_LIST_FOR_EACH macro. It should give you an idea of how to do what you want.
Quote:
#define LIST (w, (x, (y, (z, BOOST_PP_NIL))))

#define MACRO(r, data, elem) BOOST_PP_CAT(elem, data)

BOOST_PP_LIST_FOR_EACH(MACRO, _, LIST) // expands to w_ x_ y_ z_


I dont quite see how this macro would allow me to insert JUST the names into an existing loop or a block of code. Can somebody please post a little demonstration if it is possible?

It seems like BOOST_PP_REPEAT would work IF I could figure out how to use the index counter to iterate through some kind of 'name list' as well..
Are you familar with the token-pasting operator (##)? I haven't used it in awhile but it may be what you're looking for.

This may be Visual C++ specific as well, if that matters.

Good luck,
Geoff
I dont think the problem is joining things together, but rather - How can you create a list/vector that can be read at the preprocessor stage.
Quote:Original post by ZealousEngine
There are many times where I find myself writing dozens of lines of code where there is only a minor difference from line to line (a name for example). A good example is my function map. I have a list of component names, and I want to map each unique name to a unique function (since its faster than a big switch statement)...

Quote:
mFuncMap[meshId] = &funcMesh
mFuncMap[particleEffectId] = &funcParticleEffect
mFuncMap[rigidBodyId] = &funcRigidBody


In the above case each unique component (mesh, particle effect, ect..) maps to a unique function. But it really bugs me that I have to write all this out long hand, when there SHOULD be a way to create some kind of loop...

Quote:
for ( int i = 0; i < numComponents; ++i ) {
mFuncMap[getComId(i)] = &func'MACRO_getComName(i)';
}


Is there anyway to do the above?

Thanks!


I usually achieve this like so:
#define LIST_MY_STUFF( F,                  A, B, C )	\ 	F( mesh,           Mesh,           A, B, C )	\ 	F( particleEffect, ParticleEffect, A, B, C )	\ 	F( rigidBody,      RigidBody,      A, B, C )	//#define FUNC_MAP( L, U, A, B, C )	\ 	mFuncMap[L##Id] = &func##U;	//LIST_MY_STUFF( FUNC_MAP, unused, unused, unused );

^^ A, B and C are just there if you need to pass in any arguments. They're not used so I've just chucked 'unused' there - you can put any crap you want (boost chooses to use ~ for unused macro arguments) or if none of your macros require extra arguments you can get rid of A,B,C altogether (or if you need more than 3 arguments you can add D,E,F,G...).

If you need to call another function for each thing in the list, just make a new macro like FUNC_MAP, and then do the for-each using LIST_MY_STUFF.

[EDIT]N.B. if you're copy/pasting my code, I had to insert a space after each back-slash to make the forum accept the code ;) Make sure to remove these spaces if you want to try and compile it.

[EDIT2] I'm sure this can be done with boost as well, but IMO this is a lot simpler and easier for non-boost-acquainted people to come to grips with.

[EDIT3] I'm not sure if this is portable, but it works with MSVC 6 - MSVC 2008 (I haven't tested with GCC, etc.)

This topic is closed to new replies.

Advertisement