2

有没有办法禁用转换运算符?将它们标记为“=删除”会弄乱其他事情。

考虑以下代码:

class Foo
{
public:

    Foo() :mValue(0) {}
    ~Foo() = default;
    Foo(int64_t v) { mValue = v; }
    Foo(const Foo& src) = default;

    bool operator==(const Foo& rhs) { return mValue == rhs.mValue; }

    /* after commenting these lines the code will compile */
    operator int() const = delete;
    operator int64_t() const = delete;

private:
    int64_t mValue;
};

int main()
{
    Foo foo1(5);
    Foo foo2(10);
    bool b1 = (foo1 == foo2);
    bool b2 = (foo1 == 5);
}

这不会编译,因为 gcc 抱怨 == 运算符不明确:

test.cc: In function ‘int main()’:
test.cc:25:21: error: ambiguous overload for ‘operator==’ (operand types are ‘Foo’ and ‘int’)
     bool b2 = (foo1 == 5);
                     ^
test.cc:25:21: note: candidates are:
test.cc:25:21: note: operator==(int, int) <built-in>
test.cc:25:21: note: operator==(int64_t {aka long int}, int) <built-in>
test.cc:10:10: note: bool Foo::operator==(const Foo&)
     bool operator==(const Foo& rhs) { return mValue == rhs.mValue; }
          ^

但是,在注释了转换运算符之后,代码将很好地编译和运行。

第一个问题是:为什么删除的转换运算符会给 == 运算符造成歧义?我认为他们应该禁用隐式 Foo -> int 转换,但它们似乎会影响 int -> Foo 转换,这对我来说听起来不合逻辑。

第二个:有没有办法将转换运算符标记为已删除?是的,通过不声明它们——但我正在寻找一种方式,让未来的任何人都能看到这些转换被设计禁用。

4

2 回答 2

3

对已删除函数的任何使用都是格式错误的(程序将无法编译)。

如果该函数被超载,则首先进行过载分辨率,并且只有在选择删除功能时才对程序进行不正确的形式。

在您的情况下,程序无法选择转换,因为您有 3 个变体

  • 整数 -> Foo

  • 富 -> 整数

  • 富 -> int64

第二个问题:您可以保持原样,但始终对 int 使用显式转换

bool b2 = (foo1 == Foo(5));
于 2016-11-15T11:24:59.923 回答
2

以下是我认为问题的症结所在:

[dcl.fct.def.delete]

隐式或显式引用已删除函数(而不是声明它)的程序是格式错误的。
...
已删除的函数隐含地是内联函数 ([dcl.inline])。

[class.member.lookup/4]

如果 C 包含名称为 f 的声明,则声明集包含在 C 中声明的每个满足查找发生的语言构造要求的 f 声明。

即使你delete是函数,你仍然声明它。声明的函数将参与重载决议。只有当它是已解决的重载时,编译器才会检查它是否被删除。

在您的情况下,存在这些函数声明时存在明显的歧义。

于 2016-11-15T11:27:16.140 回答