哈希标记(#)在对象宏扩展列表中起什么作用? 我一直试图理解C++预处理器中宏扩展的描述,如C++ 14标准的早期草案中所描述的。(这是我可以免费获得的版本,我怀疑自那以后预处理器的变化有多大。)

哈希标记(#)在对象宏扩展列表中起什么作用? 我一直试图理解C++预处理器中宏扩展的描述,如C++ 14标准的早期草案中所描述的。(这是我可以免费获得的版本,我怀疑自那以后预处理器的变化有多大。),c++,C++,草案举了一个例子: #define hash_hash # ## # 这表明它扩展为##。我已经验证了g++具有这种行为。但我在标准的实际规范性文本中找不到对此的解释,它解释了#在函数宏中的参数名称将相应的参数字符串化之前(我完全理解),但没有说明它在任何其他上下文中的含义 当我看到这一点时,我更加困惑了 #define pound # 扩展为#,完全符合我最初的预期 该示例演示如何“转义”宏中的两个哈希序列。它接受第一个和最后一个散列,并使用中间的双散列将它们连接起来,当在另一个宏中使用时

草案举了一个例子:

#define hash_hash # ## #
这表明它扩展为##。我已经验证了g++具有这种行为。但我在标准的实际规范性文本中找不到对此的解释,它解释了#在函数宏中的参数名称将相应的参数字符串化之前(我完全理解),但没有说明它在任何其他上下文中的含义

当我看到这一点时,我更加困惑了

#define pound #

扩展为#,完全符合我最初的预期

该示例演示如何“转义”宏中的两个哈希序列。它接受第一个和最后一个散列,并使用中间的双散列将它们连接起来,当在另一个宏中使用时,将双散列序列置于输出上。在宏的中间没有其他方法来写双散列,而不必将相邻散列连接起来,消失。
<>这是因为C++被设计成一次编译,所以一旦预代码处理到>< < /代码>,就不能再“预处理”。它接受第一个和最后一个散列,并使用中间的双散列将它们连接起来,当在另一个宏中使用时,将双散列序列置于输出上。在宏的中间没有其他方法来写双散列,而不必将相邻散列连接起来,消失。
<>这是因为C++是一次编译的,所以一旦代码“>代码→< /COD>序列被预处理器预处理成<代码>< <代码>,它就永远不会被预处理。同样。

####
扩展为
##
并不是关于字符串化操作,而是由于令牌串联操作符
#
。我想,这个例子解释了##在展开时不是一个串联运算符,例如``c hash#u hash c``完全展开为
c##d
。这让我更加困惑。这个例子展示了如何“转义”宏中的两个哈希序列。它接受第一个和最后一个散列,并使用中间的双散列连接它们,当在另一个宏中使用时,将双散列序列放在输出上。没有其他方法来在宏的中间写双哈希,而没有将相邻的标记连接起来,消失。谢谢你,马德卡雷尔。这就相当清楚了。因此,两个哈希的串联产生一个不是串联运算符的单双哈希令牌。我会回到《标准》来更好地理解为什么会这样。@MadKarel——听起来是个答案(也是个好答案)——你应该把它作为一个答案来写,而不是写在评论中!将
#####
扩展为
##
与字符串化操作无关,而是由于令牌连接操作符
#
。我想,这个例子解释了##在展开时不是一个串联运算符,例如``c hash#u hash c``完全展开为
c##d
。这让我更加困惑。这个例子展示了如何“转义”宏中的两个哈希序列。它接受第一个和最后一个散列,并使用中间的双散列连接它们,当在另一个宏中使用时,将双散列序列放在输出上。没有其他方法来在宏的中间写双哈希,而没有将相邻的标记连接起来,消失。谢谢你,马德卡雷尔。这就相当清楚了。因此,两个哈希的串联产生一个不是串联运算符的单双哈希令牌。我会回到《标准》来更好地理解为什么会这样。@MadKarel——听起来是个答案(也是个好答案)——你应该把它作为一个答案来写,而不是写在评论中!预处理器不是严格意义上的单过程,因为宏扩展是重新扫描的,这是一种有限的局部第二过程。但我想我现在明白了。########将两个哈希值连接成一个###,重新扫描时不会将其视为连接运算符,因为它不是替换列表的一部分。当一个相邻令牌是一个参数名时,该标准只讨论##;您必须从示例中推断,它会将相邻的任意两个标记粘贴到替换列表中,即使这两个标记都不是参数名。预处理器不是严格意义上的单次过程,因为宏扩展会被重新扫描,这是一种有限的局部第二次过程。但我想我现在明白了。########将两个哈希值连接成一个###,重新扫描时不会将其视为连接运算符,因为它不是替换列表的一部分。当一个相邻令牌是一个参数名时,该标准只讨论##;您必须从示例中推断,它将在替换列表中粘贴与其相邻的任何两个标记,即使这两个标记都不是参数名。