简体   繁体   中英

Expansion of C++ macro within macro to be concatenated

I have to let CS students modify a group number and then generate some stuff related to that number. I don't want students to modify much but only that one group number defined somewhere as

#define GROUP_NUM 0

However, I cannot find a way to generate the rest from that MACRO. For example:

#include <iostream>
using namespace std;

// string troubles
#define STR(x) #x
#define XSTR(x) STR(x)

// the trouble
#define GROUP_NUM 0
#define CLASS_NAME Group GROUP_NUM
#define CLASS_STR XSTR(CLASS_NAME)

int main()
{
   cout << "CLASS_NAME = " << CLASS_STR << endl; 

   return 0;
}

outputs sadly

CLASS_NAME = Group 0

Here the trouble is that I don't want that space between Group and 0 because I need to use CLASS_NAME to create some class out of it such as

class CLASS_NAME : public .... { ... }

I tried to use

#define CLASS_NAME Group##GROUP_NUM

but then GROUP_NUM doesn't get expanded and it outputs

CLASS_NAME = GroupGROUP_NUM

The only solution I have found is to define these CLASS_NAME and CLASS_STR as macro functions which are passed the group number as argument (on the call site, not in another macro!):

// the trouble
#define GROUP_NUM 0
#define CLASS_NAME(g) Group ## g
#define CLASS_STR(g) XSTR(CLASS_NAME(g))

int main()
{
   cout << "CLASS_NAME = " << CLASS_STR(GROUP_NUM) << endl; 

   return 0;
}

Is there a better solution? Why doesn't the following get expanded?

#define CLASS_STR XSTR(CLASS_NAME(GROUP_NUM))

The definition of XSTR above seems to show that one can use chained macros, so I don't understand why it doesn't get expanded here.

Update : The trick of the helper macro functions is the solution. However I'd like to clarify the solution:

  1. how does the macro expansion trick work? does it fully expand directly or does it only do one round of expansion? (ie if I have imbricated macros, would it mean I need more than one layer of helper function?)
  2. the expansion with ## is still somewhat mysterious to me

My full problem was involving the nori framework and especially this . With that macro, ie

#define NORI_REGISTER_CLASS(cls, name) \
    cls *cls ##_create(const PropertyList &list) { \
        return new cls(list); \
    } \
    static struct cls ##_{ \
        cls ##_() { \
            NoriObjectFactory::registerClass(name, cls ##_create); \
        } \
    } cls ##__;

If I use NORI_REGISTER_CLASS(CLASS_NAME, "mystring"), it gets incorrectly partially expanded into

Group0 * CLASS_NAME_create (const PropertyList &list) { return new Group0 (list); } ...

But if I use one wrapper macro to call that one, it works. What is the rule for macro expansion here? Why does the first cls get expanded and the second one keeps the name?

A posible solution would be:

#include <iostream>

using namespace std;

#define CLASS_NUM 0

// String macros
#define XSTR(x) STR(x)
#define STR(x) #x

#define CONCAT(x,y) x##y
// XCONCAT will first process tokens before passing them to CONCAT
#define XCONCAT(x,y) CONCAT(x,y)

// This will generate Group0
#define CLASS_NAME XCONCAT(Group,CLASS_NUM)

// Then this will generate "Group0"
#define CLASS_STR XSTR(CLASS_NAME)

int main()
{
   cout << "CLASS_NAME = " << CLASS_STR << endl; 

   return 0;
}

With this code the output is:

CLASS_NAME = Group0

The ## operator only works on tokens. So you need a helper macro.

Try this:

#include <ostream>
#include <iostream>

// the trouble
using namespace std;
// the trouble
// string troubles
#define STR(x) #x
#define XSTR(x) STR(x)
#define GROUP_NUM 0
#define CLASS_STR(g) XSTR(Group ## g)
#define CLASS_STR2(g) CLASS_STR(g)

int main()
{
   cout << "CLASS_NAME = " << CLASS_STR2(GROUP_NUM) << endl; 

   return 0;
}

Use BOOST_PP_CAT for this:

#define CLASS_NAME BOOST_PP_CAT(Group,GROUP_NUM)

http://www.boost.org/doc/libs/1_54_0/libs/preprocessor/doc/ref/cat.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM