我在头文件中有一个函数:
template <int line>
inline void log() {}
然后我尝试这个技巧让它更容易使用:
#define LOG_LINE log<__LINE__>()
然后在.cpp文件中我做:
void main()
{
LOG_LINE;
}
似乎它按照我喜欢的方式工作。我从.cpp文件获取行,而不是在.h文件中声明LOG_LINE
的行。但我不明白它是如何工作的。 C ++是否会通过双重预处理,为第二次传递留下像__LINE__
这样的特殊宏?这是便携式(标准)行为吗?我是否应该期望这适用于所有主要的C ++编译器?到目前为止,我只尝试过MSVC。
答案 0 :(得分:5)
应该区分整个输入的传递次数,这是单次传递通常引用的术语,以及嵌套扩展的处理。预处理器通常会在文件中一次性扩展所有宏,但它会正确扩展展开的表单,直到没有任何内容可以展开。
也就是说,LOG_LINE
扩展到log<__LINE__>()
,其中__LINE__
再次扩展到3
,产生最终扩展log<3>()
- 所有这些都在一个通过编译单元。
答案 1 :(得分:3)
是的,这是可移植的标准行为。是的,你可以依赖它。
原因是#define命令只是存储构成扩展文本的标记,而无需解释或扩展它。因为它们是令牌,所以不存储空格和注释。
然后,当程序文本中的宏名称使用时,它将被扩展文本(以及任何需要的参数)替换。然后扫描并替换替换文本中的任何标记,依此类推(除了没有递归替换)。
在您的情况下,需要两次扩展才能获得基础行号。
见N3797 16.3。对于标准文档,它相对可读。有些例子与您提出的要求非常接近。
答案 2 :(得分:2)
这不需要双通道预处理。这是关于嵌套宏的扩展顺序(在某种意义上,表达式在扩展所有嵌套宏时根据需要扩展了多个传递)。来自this question的回答的引用:
##运算符之后没有出现的所有参数或者##的任何一个都在被替换时完全宏扩展,而不是在扩展类函数宏之前。