Есть ли способ отключить операторы преобразования? Отмечая их «= delete» портит другие вещи.
Рассмотрим следующий код:
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, что не звучит для меня логично.
Второй: есть ли способ пометить операторы преобразования как удаленные? Да, не объявляя их — но я ищу способ, которым любой в будущем увидит, что эти преобразования отключены по дизайну.
Вот что я думаю, суть вопроса:
Программа, которая ссылается на удаленную функцию неявно или явно, кроме как для ее объявления, является неправильно сформированной.
…
Удаленная функция неявно является встроенной функцией ([dcl.inline]).
Если C содержит декларацию имени f, декларация установлена
содержит каждое объявление f, объявленное в C, которое удовлетворяет
требования языковой конструкции, в которой происходит поиск.
Даже если ты delete
функция, вы все еще объявляете это. И объявленная функция будет участвовать в разрешении перегрузки. Только когда это разрешенная перегрузка, компилятор проверяет, был ли он удален.
В вашем случае существует явная неоднозначность, когда присутствуют эти объявления функций.
Любое использование удаленной функции некорректно (программа не
компиляции).Если функция перегружена, сначала выполняется разрешение перегрузки,
и программа плохо работает, если удаленная функция
выбран.
В вашем случае программа не может выбрать конверсию, потому что у вас есть 3 варианта
int -> Foo
Foo -> int
Foo -> int64
Второй вопрос:
Вы можете оставить все как есть, но всегда используйте явное преобразование для int
bool b2 = (foo1 == Foo(5));