Pregunta

Tengo un comportamiento extraño con un operador sobrecargado en C++.Tengo una clase y necesito verificar si su contenido es mayor o igual a un doble largo.Sobrecargué el operador >= para hacer esta verificación, mi declaración es la siguiente:

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

Debo decir que también tengo un operador doble de conversión a largo para mi clase, que funciona sin excepciones solo bajo ciertas condiciones.Ahora, cuando uso este operador, el compilador se queja de que hay un uso ambiguo de operador>= y las alternativas son:

  • Mío.
  • el incorporado operator>=(long double, int).

Ahora bien, ¿cómo fuerzo al programa a utilizar mi operador?

¿Fue útil?

Solución

Actualización de 2015: O, si desea mantener la capacidad de conversión usando la sintaxis (double)obj lugar la sintaxis obj.to_double(), hacer que la función de conversión explicit prefijándolo con esa palabra clave. Es necesario una conversión explícita a continuación, para la conversión a disparar. Personalmente, prefiero la sintaxis .to_double, a menos que la conversión sería bool porque en ese caso la conversión es utilizado por if(obj) incluso si es explicit, y eso es mucho más fácil de leer que if(obj.to_bool()) en mi opinión.


La caída de la conversión del operador. Esto causará problemas hasta el final. Tienen una función como

to_double()

o similar, que devuelve el valor doble y llamar a esa función explícita para obtener un doble.

Para el problema que nos ocupa, no existe este problema:

obj >= 10

Tenga en cuenta que la expresión. El operador incorporado coincide con el primer argumento por una secuencia de conversión definida por el usuario para su tipo usando el operador de conversión doble largo (). Sin embargo, su función coincide con el segundo argumento por una secuencia estándar de conversión de int a long double (integral a la conversión de coma flotante). Siempre es ambigua cuando hay conversiones de dos argumentos, pero no al menos un argumento que se puede convertir mejor, mientras que el resto de argumentos no se convierten peor para una llamada. En su caso, el orden interna coincide con el segundo argumento mejor, pero la primera es peor, pero su función coincide con el primer argumento mejor, pero el segundo peor.

Es confuso, así que aquí están algunos ejemplos (conversiones de char a int están llamados promociones, que son mejores que las conversiones de char a algo que no sea int, que se llama una conversión):

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

Llama a la primera versión. Debido a que todos los argumentos a favor de la primera se pueden convertir mejor. Igualmente, el siguiente todavía llamará a la primera:

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

Debido a que el primero se puede convertir mejor, y el segundo no se convierte peor. Pero el siguiente es ambigua

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

Es más interesante en este caso. La primera versión acepta el primer argumento de una coincidencia exacta. La segunda versión acepta el segundo argumento de una coincidencia exacta. Pero ambas versiones no aceptan su otro argumento al menos igual de bien. La primera versión requiere una conversión para su segundo argumento, mientras que la segunda versión requiere una promoción para su argumento. Así, a pesar de una promoción es mejor que una conversión, la llamada a la segunda versión falla.

Es muy similar a tu caso anterior. A pesar de que una secuencia estándar de conversión (conversión de int / float / double a largo doble) es mejor que una secuencia de conversión definida por el usuario (conversión de MiClase a largo doble), su versión operador no elegidos, porque su otro parámetro (tiempo doble) requiere una conversión a partir del argumento que es peor que lo que necesita el operador de orden interna para ese argumento (coincidencia perfecta).

resolución de sobrecarga es un asunto complejo en C ++, por lo que uno puede imposible recordar todas las reglas sutiles en él. Sin embargo, conseguir el plan aproximado es muy posible. Espero que le ayuda.

Otros consejos

Al proporcionar una conversión implícita a un double estás diciendo efectivamente, mi clase es equivalente a una double y por esta razón no debería importarle si el operador integrado >= para doubleSe utiliza s.Si usted hacer cuidado, entonces tu clase realmente no es "equivalente" a una double y usted debería considerar no proporcionar un implícito conversión a double, sino que en lugar de proporcionar una explícito Función miembro GetAsDouble o ConvertToDouble.

La razón por la que tienes una ambigüedad en este momento es que para una expresión t >= d dónde t es una instancia de tu clase y d es un doble, el compilador siempre tiene que proporcionar una conversión del lado izquierdo o derecho para que la expresión sea realmente ambigua.Cualquiera t's operator double se llama y el operador incorporado >= para doubles se utiliza, o d debe ser promovido a un long double y se utiliza su operador miembro >=.

Edite, actualizó su pregunta para sugerir que su conversión es demasiado larga y su comparación es con un int.En cuyo caso el último párrafo debería decir:

La razón por la que tienes una ambigüedad en este momento es que para una expresión t >= d dónde t es una instancia de tu clase y d es un int, el compilador siempre tiene que proporcionar una conversión del lado izquierdo o derecho para que la expresión sea realmente ambigua.Cualquiera t's operator long double se llama y el operador incorporado >= para long double y int se utiliza, o d debe ser promovido a un long double y se utiliza su operador miembro >=.

Asumo que está comparando contra un int literal, y no un long double:

MyClass o;

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

Si ese es el caso, ambas alternativas son tan buenos / complejo.

Usando su operator long double():

  1. MyClass::operator long double()
  2. incorporado operator>=(long double, int)

Usando su MyClass::operator>=(long double):

  1. incorporado int conversión a long double
  2. MyClass::operator>=(long double)

Hay que long double en la declaración. Intente cambiar a double.

El uso de la sobrecarga de operadores combina con la fundición de encargo puede ser muy confuso para los usuarios de su clase. Pregúntese, serían los usuarios de esta clase esperar para convertir en sí en un doble, o sea comparable con un doble? no tiene una función .greaterThan (doble) lograr el mismo objetivo pero sin sorprender al usuario?

Creo que siempre se puede convertir explícitamente el objeto de duplicar antes de comparar, para evitar la ambigüedad. Pero si yo fuera usted me reconsiderar el enfoque anterior y centrarse en la escritura de código que es intuitivo y se comporta de una manera sorprendente, en lugar del elegante tipo de fundición y el operador de sobrecarga.

(Inspirado por maravillosa sobre la sobrecarga de operadores )

  • El operador incorporado> = (tiempo doble, int).

Parece que ha definido:

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

Y se echa en falta:

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

Así que el compilador no puede decidir qué forma de convertir. (Es ambigua.)

Tal vez una función de plantilla (o método) serían útiles?

Cuidado para las situaciones donde a> = b invoca diferentes métodos que b> = a .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top