Странное поведение с оператором> = перегрузка - PullRequest
2 голосов
/ 15 февраля 2009

У меня странное поведение с перегрузкой операторов в C ++. У меня есть класс, и мне нужно проверить, больше или равно ли его содержимое длинный double. Я перегрузил оператор> =, чтобы выполнить эту проверку, мое объявление выглядит следующим образом:

bool MyClass::operator>=(long double value) const;

Я должен сказать, что у меня также есть оператор приведения к длинному двойному для моего класса, который работает без исключений только при определенных условиях. Теперь, когда я использую этот оператор, компилятор жалуется на неоднозначное использование оператора> = и альтернативы:

  • Mine.
  • Встроенный operator>=(long double, int).

Теперь, как заставить программу использовать мой оператор?

Ответы [ 6 ]

3 голосов
/ 15 февраля 2009

Предоставляя неявное преобразование в double, которое вы фактически указываете, мой класс эквивалентен double, и по этой причине вам не следует возражать, если встроенный оператор> = для double s используемый. Если вы делаете заботу, то ваш класс на самом деле не «эквивалентен» double, и вам следует подумать о том, чтобы не обеспечить неявное преобразование в double, а вместо этого предоставить явное GetAsDouble или функция-член ConvertToDouble.

Причина, по которой у вас есть неоднозначность в данный момент, заключается в том, что для выражения t >= d, где t является экземпляром вашего класса, а d является двойным, компилятор всегда должен обеспечивать преобразование либо левая сторона или правая сторона, поэтому выражение действительно неоднозначно. Либо t 's operator double вызывается и используется встроенный оператор> = для double s, либо d должен быть повышен до long double, а ваш членский оператор> = используется.

Редактируйте, вы обновили свой вопрос, чтобы предположить, что ваша конверсия увеличена вдвое, и вы сравниваете ее с int. В этом случае последний абзац должен гласить:

Причина, по которой у вас есть неоднозначность в данный момент, заключается в том, что для выражения t >= d, где t - это экземпляр вашего класса, а d - это int, компилятор всегда должен обеспечивать преобразование либо левая сторона, либо правая сторона, поэтому выражение действительно неоднозначно. Либо вызывается t operator long double, и используется встроенный оператор> = для long double и int, либо d должен быть преобразован в long double, а ваш членский оператор> = используется.

3 голосов
/ 15 февраля 2009

2015 обновление: Или, если вы хотите сохранить возможность преобразования с использованием синтаксиса (double)obj вместо синтаксиса obj.to_double(), сделайте функцию преобразования explicit, добавив префикс к этому ключевому слову. Вам нужно явное приведение, чтобы преобразование сработало. Лично я предпочитаю синтаксис .to_double, если только преобразование не будет к bool, потому что в этом случае преобразование используется if(obj), даже если оно explicit, и это значительно более читабельно, чем if(obj.to_bool()) в мое мнение.


Отбросьте оператор преобразования. Это будет вызывать проблемы на всем пути. Есть функция, как

to_double()

Или аналог, который возвращает значение double и явно вызывает эту функцию, чтобы получить значение double.

Для рассматриваемой проблемы есть эта проблема:

obj >= 10

Рассмотрим это выражение. Встроенный оператор сопоставляет первый аргумент определенной пользователем последовательности преобразования для вашего типа с помощью оператора преобразования long double (). Но ваша функция соответствует второму аргументу по стандартной последовательности преобразования из int в long double (интеграл в преобразование с плавающей запятой). Это всегда неоднозначно, когда есть преобразования для двух аргументов, но нет хотя бы одного аргумента, который можно преобразовать лучше, в то время как остальные аргументы не преобразуются хуже для одного вызова. В вашем случае встроенный лучше соответствует второму аргументу, но первый хуже, но ваша функция лучше соответствует первому аргументу, а второму - хуже.

Это сбивает с толку, поэтому вот несколько примеров (преобразования из char в int называются рекламными акциями, которые лучше, чем преобразования из char в нечто иное, чем int, что называется конверсией):

void f(int, int);
void f(long, long);
f('a', 'a');

Вызывает первую версию. Потому что все аргументы для первого могут быть преобразованы лучше. Точно так же следующее все равно будет вызывать первое:

void f(int, long);
void f(long, long);
f('a', 'a');

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

void f(char, long);
void f(int, char);
f('a', 'a'); // ambiguous

В этом случае интереснее. Первая версия принимает первый аргумент с точным соответствием. Вторая версия принимает второй аргумент с точным соответствием. Но обе версии не принимают их другой аргумент по крайней мере одинаково хорошо. Первая версия требует преобразования для своего второго аргумента, в то время как вторая версия требует повышения для своего аргумента. Таким образом, несмотря на то, что продвижение лучше конверсии, вызов ко второй версии не удался.

Это очень похоже на ваш случай выше. Даже если стандартная последовательность преобразования (преобразование из int / float / double в long double) на лучше , чем определяемая пользователем последовательность преобразования (преобразование из MyClass в long double), версия вашего оператора не выбрана, поскольку Ваш другой параметр (long double) требует преобразования аргумента, который хуже, чем встроенный оператор для этого аргумента (идеальное соответствие).

Разрешение перегрузки - это сложный вопрос в C ++, поэтому в нем невозможно запомнить все тонкие правила. Но получить грубый план вполне возможно. Я надеюсь, что это поможет вам.

1 голос
/ 15 февраля 2009

Я полагаю, вы сравниваете литерал int, а не long double:

MyClass o;

if (o >= 42)
{
   // ...
}

В этом случае обе альтернативы являются хорошими / сложными.

Использование вашего operator long double():

  1. MyClass::operator long double()
  2. встроенный operator>=(long double, int)

Использование вашего MyClass::operator>=(long double):

  1. встроенное преобразование int в long double
  2. MyClass::operator>=(long double)
0 голосов
/ 15 февраля 2009
  • Встроенный оператор> = (long double, int).

Похоже, вы определили:

bool class::operator>=(long double value) { return value >= classValue; }

А вам не хватает:

bool class::operator>=(double value)      { return value >= classValue; }
bool class::operator>=(int value)         { return value >= classValue; }

Таким образом, компилятор не может решить, какой способ конвертировать. (Это неоднозначно.)

Возможно, шаблонная функция (или метод) будет полезна?

Остерегайтесь ситуаций, когда a> = b вызывает методы, отличные от b> = a .

0 голосов
/ 15 февраля 2009

Использование вами перегрузки операторов в сочетании с кастомизацией может очень запутать пользователей вашего класса. Спросите себя, будут ли пользователи этого класса ожидать того, что он превратится в двойной, или будет сравним с двойным? Разве если бы функция .greaterThan (double) не достигла той же цели, но не удивила пользователя?

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

(Вдохновлен замечательной FQA о перегрузке оператора )

0 голосов
/ 15 февраля 2009

У вас есть long double в объявлении. Попробуйте изменить его на double.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...