【问题标题】:C++ macro '##' doesn't work after '->' operatorC++ 宏 '##' 在'->' 运算符之后不起作用
【发布时间】:2026-01-28 12:00:01
【问题描述】:

我有一个shared_ptr对象x,它有如下get和set方法:

x->a_value();
x->set_a_value();
x->b_value();
x->set_b_value();

当我尝试定义宏时:

#define MAC(type) \
  x->set_##type##_value(val);

MAC(a)

它工作正常,但是当我这样做时:

#define MAC(type) \
  x->##type##_value();

MAC(a)

它给出以下编译错误: pasting formed '->a', an invalid preprocessing token

【问题讨论】:

    标签: c++ c++11 macros


    【解决方案1】:

    它在锡上写的:->a 不是一个单一的、有效的预处理器令牌:它是两个令牌。此处无需粘贴。

    #define MAC(type) \
      x->type##_value();
    

    【讨论】:

    • 昆汀,你是如何在回答中使用“锡”的?我无法确定这是某事的拼写错误还是我从未见过的那个词的新用法。
    • “完全按照它在锡上说的做”最初是英国的营销口号(用于清漆/油漆产品)。在这种情况下,它只是意味着“问题就是错误消息所说的”。
    • @Segfault 请参阅Exactly What It Says on the Tin。稍后谢谢我。
    • @MaskedMan 请在喜欢 tvtropes 之前发出警告,有些人打算今天工作 :)
    【解决方案2】:

    预处理器处理“令牌” - 喜欢名称和运算符。

    ## 运算符通过将较小的部分粘贴在一起来创建新令牌。在第一个示例中,set_##type##_value 变为 set_a_value,这是一个有效的令牌。

    在第二个示例中,->##type##_value 将变为->a_value,这不是有效的预处理器令牌。应该是两个token。

    如果你只写x->type##_value(); 行,它应该可以工作。您将获得单独的令牌 x->a_value();

    【讨论】:

    • 形成一个连接##的令牌的要求是否有任何特别有用的目的,而不是仅仅允许任何一方的内容在适当的情况下合并到一个令牌中?我可以看到让预处理器将 1.2E+5 和 0x1E+4 视为一个令牌而不是三个令牌的唯一优势是可以连接多个片段以形成一个浮点数,但在 @987654333 上没有该约束@没关系。
    • 这些规则可以追溯到 C 语言标准化,我不知道他们是如何发现这是它的工作方式(或应该工作)。调试宏已经很困难了,让## 操作符有时会默默地粘贴标记失败不会让这变得更容易。例如,在#if x == y 中,必须严格规定xy 的形成方式。
    • #if 的行为在很多方面都很奇怪;在稍后的翻译阶段评估的编译时条件指令将有助于避免很多奇怪之处。不过,我看不到像#define JOIN(x,y) x##y squawk 这样的东西在哪里,除非 x 的最右边的标记和 y 的最左边的标记交互有任何帮助。你对你的#if有什么想法?
    • 要问的人不是提出 C 标准的人,而是实施者。 C 标准保留了## 的行为,其中结果不会形成未定义的标记,因此已经允许实现在所有情况下静默接受##。也就是说,尚不清楚在这种情况下连接a0.1 的结果应该是什么。一个错误?单个a0.1 令牌(标准C 中不存在)?未连接的 a0.1 令牌?重新标记 a0.1 标记?我怀疑要求任何特定行为没有任何好处。
    【解决方案3】:

    令牌粘贴运算符 (##) 用于将两个令牌连接成一个 有效 令牌。

    当你写作时

    x->##type##_value();
    
    • 第一个处理的令牌是x

    • 下一个token由->type拼接而成,因为typea,拼接的结果是->a,应该是一个合法的token,但不是。

    因此,您会收到错误消息:pasting formed '->a', an invalid preprocessing token

    要解决这个问题,只需编写

    x->type##_value();
    

    这边

    • 解析的第一个令牌是x

    • 解析的下一个标记是->

    • 下一个标记是通过连接标记type(变成a)与标记_value 形成的。这给出了a_value,这是一个有效的令牌。

    • 下一个令牌是(

    • 下一个令牌是)

    • 最后一个令牌是;

    【讨论】: