c ++ оператор перегрузки bool () выдает неоднозначную ошибку перегрузки с оператором + - PullRequest
8 голосов
/ 15 марта 2011

Я компилирую некоторый код на C ++ класса MegaInt, который является классом положительного десятичного типа, который допускает арифметические операции с большими числами.

Я хочу перегрузить оператор bool, чтобы разрешить код, подобный этому:

MegaInt m(45646578676547676);  
if(m)  
    cout << "YaY!" << endl;

Это то, что я сделал:

header:

class MegaInt
{
    public:
        ...
    operator bool() const;
};

const MegaInt operator+(const MegaInt & left, const MegaInt & right);
const MegaInt operator*(const MegaInt & left, const MegaInt & right);

реализация:

MegaInt::operator bool() const
{
    return *this != 0;
}
const MegaInt operator+(const MegaInt & left, const MegaInt & right)
{
    MegaInt ret = left;
    ret += right;
    return ret;
}

Теперь проблема в том, что я делаю:

MegaInt(3424324234234342) + 5;

Это дает мне эту ошибку:

неоднозначная перегрузка для оператора "оператор +" в операторе + (const MegaInt &, const MegaInt &) примечание: кандидаты: operator + (int, int)|примечание: const MegaInt operator + (const MegaInt &, const MegaInt &) |

Не знаю почему.Как перегруженный bool () заставляет оператора + становиться неоднозначным? 10

Спасибо.


Ну, все дали мне отличные ответы, к сожалению, ни один из них, похоже, не решил мою проблемуполностью.

Оба void * или идиома Safe Bool работают. За исключением одной крошечной проблемы, я надеюсь, что есть обходной путь:

При сравнении с 0, например:

if (aMegaInt == 0)

Компилятор снова выдает неоднозначную ошибку перегрузки.Я понимаю, почему: он не знает, сравниваем ли мы значение false или значение MegaInt со значением 0. Тем не менее, в этом случае я бы хотел привести его к MegaInt (0).Есть ли способ заставить это?

Еще раз спасибо.

Ответы [ 6 ]

12 голосов
/ 15 марта 2011

Компилятору C ++ разрешено автоматически конвертировать bool в int для вас, и это то, что он хочет сделать здесь.

Способ решения этой проблемы состоит в использовании безопасной bool идиомы .

Технически, создание operator void* не является примером идиомы безопасной bool, но на практике это достаточно безопасно, потому что проблема bool / int, с которой вы сталкиваетесь, является распространенной ошибкой, и портит совершенно разумный и в противном случае правильный код (как вы видите из вашего вопроса), но злоупотребления преобразованием void* встречаются не так часто.

3 голосов
/ 15 марта 2011

Запись в Википедии о операторах явного преобразования для C ++ 0x содержит краткое изложение причины появления этой ошибки до C ++ 0x. По сути, оператор преобразования bool является целочисленным типом преобразования, поэтому он будет использоваться в интегральном арифметическом выражении. Исправление до C ++ 0x - вместо этого использовать void * в качестве оператора преобразования; void * может быть преобразовано в логическое выражение, но не в интегральное выражение.

2 голосов
/ 15 марта 2011

Как говорит ответ Эрика, проблема в том, что, предоставляя неявное преобразование в bool, вы открываете дверь для выражений, которые могут означать несколько вещей;в этом случае компилятор будет жаловаться на неоднозначность и сообщит вам об ошибке.

Однако учтите, что предоставление неявного *1007* преобразования в void* не отпустит вас;это просто изменит набор выражений, которые представляют проблему.

Существует два герметичных решения этой проблемы:

  • Сделайте преобразование в bool явным (что может быть нежелательно)если класс представляет сущность с интуитивно понятным значением «истина / ложь»)
  • Используйте идиома безопасного bool (это действительно охватывает все основы, но столько же хороших вещей в жизни и C ++ естьслишком сложно - вы платите цену)
1 голос
/ 15 марта 2011

Проблема в том, что bool может свободно конвертировать в int. Таким образом, выражение MegaInt(3424324234234342) + 5; может быть одинаково правильно истолковано следующим образом:

(bool)(MegaInt(3424324234234342)) + 5;

или

MegaInt(3424324234234342) + MegaInt(5);

Каждое из этих выражений включает одно пользовательское преобразование и является равным в глазах компилятора. По этой причине преобразование в bool весьма проблематично. Было бы неплохо иметь способ сказать, что это должно происходить только в контексте, который явно требует bool, но это не так. : - /

Преобразование в void *, которое предлагает кто-то другой, является обходным путем, но я думаю, что в качестве обходного пути у него есть свои проблемы, и я бы не стал этого делать.

0 голосов
/ 03 декабря 2013

Другие упоминают идиому Safe Bool.Однако для таких объектов, как ваш, было бы плохой идеей добавить всю эту неприятную, особую логику, когда вам все равно нужна полная поддержка алгебры.

Вы определяете пользовательский целочисленный тип.Вы получите гораздо больше за свои усилия, определив «operator ==» и «operator! =», А затем реализовав «operator bool ()» примерно так:

operator bool()
{
   return (*this != 0);
}

Только из этих 3 функций вы получите всеидиом «если» для целых чисел, и они будут вести себя так же, как и встроенные: «if (a == b)», «if (a! = b)», «if (а) "," если (! а) ".Ваше неявное правило "bool" также будет (если вы осторожно) работать также интуитивно.

Кроме того, полная идиома Safe Bool не нужна.Подумайте об этом - единственное, что вам нужно, это: «1) сравнение 2 объектов плохо определено или не определено, 2) приведение к (int) или другие типы примитивов должны быть защищены и 3) валидность объекта четко определена (фактический источник возвращаемого bool). "

Ну, 2) - это только соображение, если вы действительно хотите ПОДДЕРЖИВАТЬ приведение к числовому типу, например, int или float.Но для объектов, у которых НЕТ четко определенного понятия равенства (# 1), предоставление таких приведений неизбежно создает риск самой логики «if (a == b)», от которой якобы вас защищает идиома.Просто объявите "operator int ()" и такой закрытый, как вы делаете с копией ctor для не копируемых объектов, и покончите с этим:

class MyClass {
private:
   MyClass(const MyClass&);
   operator int();
   operator long();
   // float(), double(), etc. ...
public:
   // ctor & dtor ..
   bool operator==(const MyClass& other) const { //check for equality logic... }
   bool operator!=(const MyClass& other) const { return !(*this == other); }
   operator bool() { return (*this != 0); }
};
0 голосов
/ 15 марта 2011
MegaInt(3424324234234342) + 5;

MegaInt + int;

Должен ли компилятор преобразовывать ваш MegaInt в интеграл (bool является целочисленным типом) или целое число в MegaInt (у вас есть конструктор int)?

Вы исправите это, создав operator void * вместо operator bool:

operator void *() const { return (*this != 0) ? ((void *) 1) : ((void *) 0); }

...