2009-02-15 2 views
2

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

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

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

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

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

ответ

3

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


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

to_double() 

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

Для решаемой задачи, есть такая проблема:

obj >= 10 

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

Это сбивает с толку, так вот некоторые примеры (преобразования из полукокса в Int называются акции, которые лучше, чем преобразования из полукокса в нечто иное, чем 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 to long double) является лучше, чем пользовательская последовательность преобразований (преобразование из MyClass в long double), ваша версия оператора не выбрана, потому что ваш другой параметр (long double) требует преобразования из аргумента, который хуже, чем того требует встроенный оператор для этого аргумента (идеальное совпадение).

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

0

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

+0

Извините, я имел в виду длинный двойной везде. – tunnuz

0

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

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

(Вдохновленный замечательный rant about operator overloading в FQA в)

3

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

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

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

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

1

Я предполагаю, что вы сравниваете против буквального 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

Я на самом деле сравниваю с длинным двойным. – tunnuz

0
  • Встроенный оператор> = (длинный двойной, целое).

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

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

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

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

упускают для ситуаций, когда > = Ь вызывает различные методы, чем б > = а.

Смежные вопросы