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