C++中.*与->*指向成员访问运算符行为差异的标准解释问询
C++
.* 与 ->* 运算符的右操作数转换差异解析 核心差异的根源在于C++标准对两个运算符的右操作数类型要求及重载决议规则的区别:
1. .* 运算符的严格类型要求
根据C++标准[N4868] §7.6.4.2(指针到成员访问运算符)第1款:
表达式
E1.*E2是指针到成员访问表达式。E1的类型必须是类类型T或类类型T的引用。E2的类型必须是T或T的派生类的指针到成员类型。
标准附带的注释进一步明确:
[注:不会考虑从
E2到指针到成员类型的隐式转换序列。— 结束注]
这意味着.*的右操作数必须直接是指针到成员类型,不允许通过用户定义的隐式转换(比如你测试用的Offset类的转换函数)将其他类型转换为指针到成员类型,这就是编译器对s.*offset报错的原因。
2. ->* 运算符的宽松转换规则
对于->*运算符,标准§7.6.4.3第1款规定:
表达式
E1->*E2被转换为等价形式(*(E1)).*E2,除非表达式E1只被求值一次。
但关键差异体现在重载决议阶段:使用原生->*运算符时,编译器会尝试将右操作数隐式转换为所需的指针到成员类型。这是因为->*的内置候选函数允许右操作数通过隐式转换(包括用户定义的转换)匹配指针到成员类型的参数。
当你将Offset的转换函数设为explicit后,隐式转换被禁止,->*运算符无法将offset转换为指针到成员类型,因此也会报错,这符合预期。
总结
.*:右操作数必须是原生指针到成员类型,不允许任何隐式转换(包括用户定义的转换)。->*:右操作数可以是可隐式转换为指针到成员类型的任意类型,重载决议会自动触发转换。
内容的提问来源于stack exchange,提问作者ngmr80
相关产品推荐
相关产品推荐

