在预处理阶段,__LINE__扩展了哪一点?

时间:2014-03-07 12:45:09

标签: c++ c-preprocessor

我在头文件中有一个函数:

template <int line>
inline void log() {}

然后我尝试这个技巧让它更容易使用:

#define LOG_LINE log<__LINE__>()

然后在.cpp文件中我做:

void main()
{
    LOG_LINE;
}

似乎它按照我喜欢的方式工作。我从.cpp文件获取行,而不是在.h文件中声明LOG_LINE的行。但我不明白它是如何工作的。 C ++是否会通过双重预处理,为第二次传递留下像__LINE__这样的特殊宏?这是便携式(标准)行为吗?我是否应该期望这适用于所有主要的C ++编译器?到目前为止,我只尝试过MSVC。

3 个答案:

答案 0 :(得分:5)

应该区分整个输入的传递次数,这是单次传递通常引用的术语,以及嵌套扩展的处理。预处理器通常会在文件中一次性扩展所有宏,但它会正确扩展展开的表单,直到没有任何内容可以展开。

也就是说,LOG_LINE扩展到log<__LINE__>(),其中__LINE__再次扩展到3,产生最终扩展log<3>() - 所有这些都在一个通过编译单元。

答案 1 :(得分:3)

是的,这是可移植的标准行为。是的,你可以依赖它。

原因是#define命令只是存储构成扩展文本的标记,而无需解释或扩展它。因为它们是令牌,所以不存储空格和注释。

然后,当程序文本中的宏名称使用时,它将被扩展文本(以及任何需要的参数)替换。然后扫描并替换替换文本中的任何标记,依此类推(除了没有递归替换)。

在您的情况下,需要两次扩展才能获得基础行号。

见N3797 16.3。对于标准文档,它相对可读。有些例子与您提出的要求非常接近。

答案 2 :(得分:2)

这不需要双通道预处理。这是关于嵌套宏的扩展顺序(在某种意义上,表达式在扩展所有嵌套宏时根据需要扩展了多个传递)。来自this question的回答的引用:

  

##运算符之后没有出现的所有参数或者##的任何一个都在被替换时完全宏扩展,而不是在扩展类函数宏之前。