Macro concatenation using the compiler defines

It should be simple, but I'm struggling to figure it out. I have PROJECT_NAME as a ( g++ ) -D define compiler, and I want to link it with some other text to form the namespace name. My current approach is this:

 #define VERSION_NAMESPACE PROJECT_NAME ## Versioning 

For my current project, I expect VERSION_NAMESPACE be Syren_DLLVersioning . Instead, I get a compiler error:

 error: 'PROJECT_NAMEVersioning' has not been declared 

But according to the g++ call, PROJECT_NAME is defined correctly:

 ccache g++ ... -DPROJECT_NAME=Syren_DLL ... 

Why is PROJECT_NAME not replaced before concatenation?

+4
source share
1 answer

The macro name does not expand when it appears next to the ## operator, so you need more layers of indirection:

 #define P_VERSION2(foo) foo ## Versioning #define P_VERSION(foo) P_VERSION2(foo) #define VERSION_NAMESPACE P_VERSION(PROJECT_NAME) 

so PROJECT_NAME expands as an argument to P_VERSION , and then concatenates to P_VERSION2 .

Section 16.3.3 [cpp.concat], clause 3, states

For both object-like and macro functions, before replacing the replacement list to replace the new macro names, each instance of the preprocessing marker ## in the substitution list (not from the argument) is deleted and the previous preprocessing token is combined with the next preprocessing token.

so that the pre-processing tokens associated with the pre-processing token ## are merged before the macro substitution is done in the replacement list. Therefore, PROJECT_NAME must be passed through another (functional) macro so that it can be replaced and combined using Versioning .

But in 16.3.1 [cpp.subst], clause 1, the standard indicates (emphasized by me)

After the arguments for calling the macro-like macro have been defined, the argument is replaced. A parameter in the substitution list , if only the previous token # or ## for pre-processing or follows the pre-processing ## token (see below), is replaced with the corresponding argument after all the macros contained in them have been expanded. Before replacing, each argument preprocessing token is completely replaced by a macro, as if they were the rest of the preprocessing file; no other pre-processing tokens.

that macro parameters are not subject to further macro expansion if they are adjacent to pre-processing token ## . Therefore, a function macro that receives PROJECT_NAME as an argument must not directly concatenate its argument with Versioning , but to extend PROJECT_NAME it must call another macro, similar to a function that finally performs concatenation.

So, in the above example with a call to ccache g++ ... -DPROJECT_NAME=Syren_DLL ... , PROJECT_NAME is replaced by Syren_DLL when P_VERSION(PROJECT_NAME) expands, which leads to P_VERSION2(Syren_DLL) , which then leads to the concatenation of Syren_DLL and Versioning .

+12
source

All Articles