c++ - singulares - probabilidad formulas básicas




¿Son== y!=Mutuamente dependientes? (10)

¿Hay alguna situación posible en la que hacer preguntas acerca de que dos objetos sean iguales no tiene sentido, pero preguntar si no son iguales no tiene sentido? (ya sea desde la perspectiva del usuario o desde la perspectiva del implementador)

Esa es una opinion. Tal vez no lo hace. Pero los diseñadores del lenguaje, al no ser omniscientes, decidieron no restringir a las personas que pudieran presentar situaciones en las que podría tener sentido (al menos para ellos).

Estoy aprendiendo sobre la sobrecarga de operadores en C ++, y veo que == y != Son simplemente algunas funciones especiales que se pueden personalizar para los tipos definidos por el usuario. Sin embargo, mi preocupación es, ¿por qué se necesitan dos definiciones separadas ? Pensé que si a == b es verdadero, entonces a != b es automáticamente falso, y viceversa, y no hay otra posibilidad, porque, por definición, a != b es !(a == b) . Y no podía imaginar ninguna situación en la que esto no fuera cierto. ¿Pero quizás mi imaginación es limitada o soy ignorante de algo?

Sé que puedo definir uno en términos del otro, pero esto no es lo que estoy preguntando. Tampoco estoy preguntando sobre la distinción entre comparar objetos por valor o por identidad. O si dos objetos podrían ser iguales y no iguales al mismo tiempo (¡esto definitivamente no es una opción! Estas cosas son mutuamente excluyentes). Lo que pregunto es esto:

¿Hay alguna situación posible en la que hacer preguntas acerca de que dos objetos sean iguales no tiene sentido, pero preguntar si no son iguales no tiene sentido? (ya sea desde la perspectiva del usuario o desde la perspectiva del implementador)

Si no existe tal posibilidad, ¿por qué en la Tierra C ++ tiene estos dos operadores definidos como dos funciones distintas?


Si no existe tal posibilidad, ¿por qué en la Tierra C ++ tiene estos dos operadores definidos como dos funciones distintas?

Debido a que puedes sobrecargarlos, y al sobrecargarlos puedes darles un significado totalmente diferente al original.

Tomemos, por ejemplo, el operador << , originalmente el operador de desplazamiento a la izquierda bit a bit, ahora comúnmente sobrecargado como operador de inserción, como en std::cout << something ; significado totalmente diferente del original.

Entonces, si acepta que el significado de un operador cambia cuando lo sobrecarga, entonces no hay razón para evitar que el usuario le dé un significado al operador == que no es exactamente la negación del operador != , Aunque esto puede ser confuso.


[..] ¿por qué se necesitan dos definiciones separadas?

Una cosa a tener en cuenta es que podría existir la posibilidad de implementar uno de estos operadores de manera más eficiente que simplemente usar la negación del otro.

(Mi ejemplo aquí fue basura, pero el punto sigue en pie, piense en los filtros de floración, por ejemplo: permiten una prueba rápida si algo no está en un conjunto, pero probar si está dentro puede llevar mucho más tiempo).

[..] por definición, a != b es !(a == b) .

Y es su responsabilidad como programador hacer eso. Probablemente sea algo bueno para escribir un examen.


Al final, lo que está comprobando con esos operadores es que la expresión a == b a != b está devolviendo un valor booleano ( true o false ). Estas expresiones devuelven un valor booleano después de la comparación en lugar de ser mutuamente excluyentes.


Con un gran poder viene de manera responsable, o al menos muy buenas guías de estilo.

== y != se pueden sobrecargar para hacer lo que quieras. Es a la vez una bendición y una maldición. No hay garantía de que != Significa !(a==b) .


En respuesta a la edición;

Es decir, si es posible que algún tipo tenga el operador == pero no el != , O viceversa, y cuándo tiene sentido hacerlo.

En general , no, no tiene sentido. La igualdad y los operadores relacionales generalmente vienen en conjuntos. Si existe la igualdad, también la desigualdad; menor que, luego mayor que y así sucesivamente con <= etc. También se aplica un enfoque similar a los operadores aritméticos, que generalmente también vienen en conjuntos lógicos naturales.

Esto se evidencia en el std::rel_ops nombres std::rel_ops . Si implementa los operadores de igualdad y menor que, el uso de ese espacio de nombres le proporciona los otros, implementados en términos de sus operadores implementados originales.

Dicho todo esto, ¿hay condiciones o situaciones en las que una no significaría inmediatamente la otra o no podría implementarse en términos de las otras? Sí, hay pocos, pero están allí; nuevamente, como se evidencia en que rel_ops es un espacio de nombres propio. Por esa razón, permitir que se implementen de forma independiente le permite aprovechar el lenguaje para obtener la semántica que necesita o necesita de una manera que sigue siendo natural e intuitiva para el usuario o cliente del código.

La evaluación perezosa ya mencionada es un excelente ejemplo de esto. Otro buen ejemplo es darles semánticas que no significan igualdad o desigualdad en absoluto. Un ejemplo similar a esto son los operadores de desplazamiento de bits << y >> se utilizan para la inserción y extracción de flujos. Aunque puede ser mal visto en los círculos generales, en algunas áreas específicas del dominio puede tener sentido.


No querrá que el idioma reescriba automáticamente a != b as !(a == b) cuando a == b devuelve algo distinto de un bool . Y hay algunas razones por las que podrías hacer que lo haga.

Es posible que tenga objetos de creación de expresiones, donde a == b no lo hace y no pretende realizar ninguna comparación, sino que simplemente crea algún nodo de expresión que representa a == b .

Es posible que tenga una evaluación diferida, donde a == b no lo hace y no pretende realizar ninguna comparación directamente, sino que devuelve algún tipo de lazy<bool> que se puede convertir a bool implícita o explícitamente más adelante realiza la comparación. Posiblemente combinado con los objetos del generador de expresiones para permitir la optimización completa de la expresión antes de la evaluación.

Es posible que tenga alguna clase de plantilla optional<T> personalizada, en la que, dada las variables opcionales t y u , desea permitir t == u , pero hacer que devuelva optional<bool> .

Probablemente hay más en lo que no pensé. Y aunque en estos ejemplos la operación a == b y a != b tienen sentido, todavía a != b no es lo mismo que !(a == b) , por lo que se necesitan definiciones separadas.


Sí, porque uno significa "equivalente" y otro significa "no equivalente" y estos términos son mutuamente excluyentes. Cualquier otro significado para estos operadores es confuso y debe evitarse por todos los medios.


Solo responderé la segunda parte de su pregunta, a saber:

Si no existe tal posibilidad, ¿por qué en la Tierra C ++ tiene estos dos operadores definidos como dos funciones distintas?

Una razón por la que tiene sentido permitir que el desarrollador sobrecargue ambos es el rendimiento. Puede permitir optimizaciones implementando ambos == y != . Entonces x != y podría ser más barato que !(x == y) es. Algunos compiladores pueden optimizarlo para usted, pero tal vez no, especialmente si tiene objetos complejos con muchas ramificaciones involucradas.

Incluso en Haskell, donde los desarrolladores se toman muy en serio las leyes y los conceptos matemáticos, uno puede sobrecargar tanto == como /= , como puede ver aquí ( http://hackage.haskell.org/package/base-4.9.0.0/docs/Prelude.html#v:-61--61- ):

$ ghci
GHCi, version 7.10.2: http://www.haskell.org/ghc/  :? for help
λ> :i Eq
class Eq a where
  (==) :: a -> a -> Bool
  (/=) :: a -> a -> Bool
        -- Defined in `GHC.Classes'

Esto probablemente se consideraría micro-optimización, pero podría estar justificado en algunos casos.


Tal vez una regla incomparable, donde a != b era falso y a == b era falso como un bit sin estado.

if( !(a == b || a != b) ){
    // Stateless
}






equality-operator