构成成员指针类型的::与*能否来自不同宏展开?合规性及消警方法
问题描述
代码示例1
#define FOO A:: struct A { int x; }; int FOO *ptr = &A::x;
使用Clang 18.1.0(无额外编译选项)编译时会触发警告:
<source>:8:5: warning: '::' and '*' tokens forming pointer to member type appear in different macro expansion contexts [-Wcompound-token-split-by-macro]
而MSVC和GCC可直接通过编译,无警告或错误。
代码示例2(宏拼接尝试)
#define CAT(x, y) CAT_(x, y) #define CAT_(x, y) x##y int CAT(FOO,*) ptr = &A::x;
三款编译器均触发错误:
error: pasting formed '::*', an invalid preprocessing token
疑问
- 依据C++标准,第一段代码是否合法?
- 若合法,除
#pragma外是否存在其他消除该警告的方式?
回答
1. 第一段代码的合法性
根据C++标准,这段代码是合法的。
C++标准允许宏展开后的标记序列被正常解析:FOO展开为A::后,会和后续的*组合成A::*(成员指针类型标记)。标准并未禁止宏拆分这类复合标记的写法,Clang的警告只是出于代码可读性或潜在风险的提示,不属于标准规定的编译错误。
2. 消除Clang警告的其他方法
除#pragma diagnostic外,还有以下几种可行方式:
- 调整宏定义:把
*整合到宏中,比如修改为#define FOO A::*,代码改为int FOO ptr = &A::x;,让::*作为整体在宏中出现,避免拆分触发警告。 - 使用类型别名:提前用
using或typedef定义成员指针类型,例如using AIntPtr = int A::*;,之后直接写AIntPtr ptr = &A::x;,彻底避开宏拆分标记的问题,代码可读性也更强。 - 关闭对应编译警告:通过编译选项
-Wno-compound-token-split-by-macro直接禁用该警告,适合不想修改代码的场景。
内容的提问来源于stack exchange,提问作者HolyBlackCat
相关产品推荐
相关产品推荐

