C++ 调用重载运算符时用户定义的枚举类隐式转换失败
考虑以下示例:C++ 调用重载运算符时用户定义的枚举类隐式转换失败,c++,c++11,operator-overloading,implicit-conversion,enum-class,C++,C++11,Operator Overloading,Implicit Conversion,Enum Class,考虑以下示例: struct ConvertibleStruct {}; enum class ConvertibleEC {}; struct Target { // Implicit conversion constructors Target(ConvertibleStruct) {} Target(ConvertibleEC) {} }; Target operator~(const Target& t) { return t; } Tar
struct ConvertibleStruct {};
enum class ConvertibleEC {};
struct Target {
// Implicit conversion constructors
Target(ConvertibleStruct) {}
Target(ConvertibleEC) {}
};
Target operator~(const Target& t) {
return t;
}
Target anotherFunction(const Target& t) {
return t;
}
int main() {
ConvertibleStruct t;
ConvertibleEC ec;
~t; // 1. Works finding the operator overloaded above
~ec; // 2. Fails to compile on clang 3.4 and gcc 4.8.2
operator~(ec); // 3. Works finding the operator overloaded above
anotherFunction(ec); // 4. Works
}
编译器版本:
上述发现适用于clang3.4
和gcc 4.8.2
。测试2。实际上,使用-std=c++11
在GCC4.7.3上编译得很好。可能是早期GCC C++11实现中的错误
断言:
- 考虑到这一点1。编译时,调用
运算符时会检查用户定义的隐式转换李>~
- 考虑到这一点,4。编译时,将检查
对象的用户定义隐式转换枚举类
- 上述断言正确吗
- 如果是,为什么是2。编译失败
- 考虑到2。无法编译,为什么3。编译
~ec
遇到了表达式中运算符的名称查找特性:[over.match.oper]/3(来自“古代”N3797):
对于一元运算符@
,其操作数类型的cv非限定版本为T1
[…]
这组非成员候选人是不合格候选人的结果
根据
非限定函数调用中名称查找的常用规则
除了忽略所有成员函数之外但是,如果没有操作数
具有类类型,仅查找集中的那些非成员函数
第一个参数类型为T1
或“参考(可能
cv合格)T1
”,当T1
是枚举类型时[…]是
候选函数
因此,::运算符~(const Target&)
不应与一元运算符应用于ConvertibleEC
类型的操作数的表达式一起找到/使用
对于第一个操作数,
~t
,操作数为类类型,上述异常不适用
第三个和第四个测试都不使用运算符查找,而是使用通常的非限定查找。通常的非限定查找会找到
::运算符~(const Target&)
(在案例1和案例3中)和另一个函数(在案例4中)。这似乎是一个标准化前的决定:我不确定其原理。有趣。这可能也解释了为什么它在gcc 4.7.3上编译。IIRC,当时GCC中的enum类
实现基于struct
s