cma*_*t85 4 c c++ c-preprocessor
这应该很简单,但我很难弄明白.我有PROJECT_NAME一个编译器(g++)-D定义,我想将它与其他一些文本连接起来形成一个命名空间名称.我目前的做法是:
#define VERSION_NAMESPACE PROJECT_NAME ## Versioning
Run Code Online (Sandbox Code Playgroud)
对于我目前的项目,我希望VERSION_NAMESPACE如此Syren_DLLVersioning.相反,我得到一个编译器错误:
error: 'PROJECT_NAMEVersioning' has not been declared
Run Code Online (Sandbox Code Playgroud)
但根据g++电话,PROJECT_NAME正在正确定义:
ccache g++ ... -DPROJECT_NAME=Syren_DLL ...
Run Code Online (Sandbox Code Playgroud)
PROJECT_NAME在连接发生之前为什么不被替换?
Dan*_*her 12
当宏名称出现在##运算符旁边时,它不会展开,因此您需要更多的间接层:
#define P_VERSION2(foo) foo ## Versioning
#define P_VERSION(foo) P_VERSION2(foo)
#define VERSION_NAMESPACE P_VERSION(PROJECT_NAME)
Run Code Online (Sandbox Code Playgroud)
所以它PROJECT_NAME被扩展为参数,P_VERSION然后连接在一起P_VERSION2.
在第16.3.3节[cpp.concat]第3段中,指明了它
对于类似对象和类似函数的宏调用,在重新检查替换列表以替换更多宏名称之前,
##删除替换列表中的预处理标记的每个实例(不是来自参数),并且连接前面的预处理标记使用以下预处理标记.
在替换列表上进行宏替换之前##,连接与预处理令牌相邻的预处理令牌.因此,必须通过另一个(类似函数)宏来传递它以进行替换和连接.PROJECT_NAMEVersioning
但是在16.3.1 [cpp.subst]第1段中,标准规定了(我强调了)
在确定了调用类函数宏的参数之后,发生了参数替换.在替换列表中的参数,除非前面有一个
#或##预处理记号或后跟一个##预处理标记(见下文),由对应的参数替换后其中所含的所有宏已经扩大.在被替换之前,每个参数的预处理标记都被完全宏替换,好像它们形成了预处理文件的其余部分; 没有其他预处理令牌可用.
如果与##预处理令牌相邻,宏参数不会受到进一步的宏扩展.因此,PROJECT_NAME作为参数接收的类似函数的宏不能直接连接其参数Versioning,但要扩展PROJECT_NAME它必须调用另一个最终进行连接的类似函数的宏.
因此,在上面,与调用ccache g++ ... -DPROJECT_NAME=Syren_DLL ...,PROJECT_NAME被替换Syren_DLL时P_VERSION(PROJECT_NAME)被膨胀,从而导致P_VERSION2(Syren_DLL)其然后导致的串联Syren_DLL和Versioning.