转换运算符名称查找的乐趣

2021-01-18 02:16:38

在撰写本文时(但可能不会持续很长时间!),Godbolt Compiler Explorer的四个主流编译器对此简单的C ++程序给出了四个不同的答案:

结构A {使用T = T1;使用U = U1;运算符U1 T1 :: *();运算符U1 T2 :: *();运算符U2 T1 :: *();运算符U2 T2 :: *();};内联自动操作which(U1 T1 :: *){return" gcc&#34 ;; } inline auto which(U1 T2 :: *){return" icc&#34 ;; } inline auto which(U2 T1 :: *){return" msvc&#34 ;; } inline auto which(U2 T2 :: *){return" clang&#34 ;; } int main(){A a;使用T = T2;使用U = U2; puts(which(a.operator U T :: *()));}

问题是应在测试范围内还是在A范围内查找U;对于T还是相同的问题。

根据当前的标准草案,听起来似乎是一致的答案是“它们都应在A的范围内查找”;也就是说,海湾合作委员会的答案是正确的,而其他人则以三种不同的方式是错误的。 [basic.lookup.unqual] / 5:

以与显示的转换功能ID相同的方式查找作为转换类型ID的类型说明符或ptr-operator的组件名称的不合格名称。如果该查找未找到任何内容,则将进行不合格的名称查找;在每种情况下,仅考虑表示类型的名称或专门针对类型的模板。

我从来不喜欢那些不考虑某些名称的查询;我敢肯定,这方面还有更多分歧。无论如何,在类型名称UT :: *中,U是类型说明符,而T :: *是ptr-operator,整个类型发音为“指向T的数据成员的指针,其中该数据成员本身是类型的U。(更简洁地说:“指向T的数据成员(类型U的指针),或“指向T的U成员的指针”。)