问题描述:

I have the following code working under msvc 2015:

#define CLASS_JS_PSG_PROPERTY_EX(PROPERTY, VALUE) \

static bool Get##PROPERTY(/*irrelevant params here...*/) \

{ \

...

some particular code

...

return true; \

}

#define CLASS_JS_PSG_PROPERTY(VALUE) \

CLASS_JS_PSG_PROPERTY_EX(##VALUE, VALUE)

...

#define kProp 1

CLASS_JS_PSG_PROPERTY_EX(Version, kProp)

CLASS_JS_PSG_PROPERTY(kProp)

This should define methods named GetVersion and GetkProp.

Now, this gives the following error under gcc C++14 (actually TDM-GCC-64):

pasting "(" and "kProp" does not give a valid preprocessing token

How should be written in order to compile under gcc C++14 and msvc 2015?

网友答案:

The trick is - if you don't want a name to get expanded as a macro, you must pass it to ## operator right away - but the result of concatenation must be a valid token. Something like this:

#include <iostream>

#define CLASS_JS_PSG_PROPERTY_EX_HELPER(GetName) \
static bool GetName() { return true; }


#define CLASS_JS_PSG_PROPERTY_EX(PROPERTY, VALUE) \
CLASS_JS_PSG_PROPERTY_EX_HELPER(Get##PROPERTY)

#define CLASS_JS_PSG_PROPERTY(VALUE) \
CLASS_JS_PSG_PROPERTY_EX_HELPER(Get##VALUE)


#define kProp 1

CLASS_JS_PSG_PROPERTY_EX(Version, kProp)

CLASS_JS_PSG_PROPERTY(kProp)

int main() {
    std::cout << GetVersion() + GetkProp();
}

Works with gcc and MSVC

The reason your original code appears to work with MSVC is because MSVC preprocessor is famously non-conforming - it operates on a stream of characters (wrong), rather than a stream of tokens (right). In CLASS_JS_PSG_PROPERTY_EX(##VALUE, VALUE), ## is not a unary operator as you suggest - it's a binary operator that glues ( and VALUE into a single token (VALUE. This is not a valid preprocessing token, so the program is ill-formed, which is what GCC complains about. But MSVC preprocessor later breaks this nonsensical token back up into pieces (which a conforming preprocessor would never do).

相关阅读:
Top