2

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.

moooeeeep
  • 31,622
  • 22
  • 98
  • 187
hernyo
  • 48
  • 4
  • Possible duplicate of [Why do C++11-deleted functions participate in overload resolution?](http://stackoverflow.com/questions/14085620/why-do-c11-deleted-functions-participate-in-overload-resolution) – moooeeeep Nov 15 '16 at 11:42
  • Setting aside the resolution problem others mentioned, it looks like you're trying to make `operator==` distribute over Foo to its member(s), and your use of `foo1 == 5` should mean that values are interchangeable with Foo constructed from values. Something like this: `template bool operator==(S && s) const { return *this == Foo(forward(s)); }` delegates to `operator==(Foo const&)` given `Foo::Foo(S &&)`. Any thoughts? – John P Mar 13 '19 at 01:13

2 Answers2

3

Any use of a deleted function is ill-formed (the program will not compile).

If the function is overloaded, overload resolution takes place first, and the program is only ill-formed if the deleted function was selected.

In you case programm can't select conversion becouse you have 3 variant

  • int -> Foo

  • Foo -> int

  • Foo -> int64

Second question: you can leave it as it is, but always use explicit conversion for int

bool b2 = (foo1 == Foo(5));
Community
  • 1
  • 1
quazeeee
  • 323
  • 2
  • 14
2

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.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458