hernyo hernyo - 24 days ago 7
C++ Question

Deleting conversion operators

Is there a way to disable conversion operators? Marking them "= delete" messes up other things.

Consider the following code:

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);
}


This won't compile because gcc complains that the == operator is ambiguous:

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; }
^


However, after commenting the conversion operators, the code will compile and run nicely.

The first question is: why do the deleted conversion operators create an ambiguity for the == operator? I thought they should disable implicit Foo -> int conversions but they seem to affect int -> Foo conversions which does not sound logic to me.

Second one: is there a way to mark the conversion operators deleted? Yes, by not declaring them - but I'm looking for a way that anyone in the future will see that those conversions are disabled by design.

Answer

Here's what I think is the crux of the matter:

[dcl.fct.def.delete]:

A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed.
...
A deleted function is implicitly an inline function ([dcl.inline]).

[class.member.lookup/4]:

If C contains a declaration of the name f, the declaration set contains every declaration of f declared in C that satisfies the requirements of the language construct in which the lookup occurs.

Even if you delete the function, you still declare it. And a declared function will participate in overload resolution. It's only when it's the resolved overload, that the compiler checks if it's deleted.

In your case, there is an obvious ambiguity when those function declarations are present.