overload operator example defining cpp c++ operator-overloading ternary-operator

c++ - operator - ¿Por qué no es posible sobrecargar al operador ternario?



operator+= c++ (5)

¿Por qué no es posible sobrecargar el operador ternario ''?:''?

Utilizo el operador ternario a menudo para consolidar las declaraciones, y siento curiosidad por qué los diseñadores de idiomas optaron por prohibir que este operador se sobrecargue. Busqué una explicación de por qué en C ++ Operator Overloading, pero no encontré una que describiera por qué esto no es posible. La única información que proporciona la nota al pie es que no se puede sobrecargar.

Mi conjetura inicial es que la sobrecarga del operador casi siempre violará el número uno o dos de los principios dados en el enlace anterior. El significado de la sobrecarga rara vez será obvio o claro o se desviará de su semántica conocida original.

Así que mi pregunta es más acerca de por qué esto no es posible y no cómo, ya que sé que no se puede hacer.


Creo que la razón principal en el momento en que no parecía valer la pena el esfuerzo de inventar una nueva sintaxis solo para ese operador. No hay token ?: , Por lo que tendría que crear una serie de reglas gramaticales especiales solo para ello. (La regla gramatical actual tiene operator seguido por un operador, que es un token único).

Como hemos aprendido (por experiencia) a usar la sobrecarga del operador de manera más razonable, se ha hecho evidente que no deberíamos haber permitido la sobrecarga de && y || O bien, por las razones que han señalado otras respuestas, y probablemente no también la coma del operador (ya que las versiones sobrecargadas no tendrán el punto de secuencia que el usuario espera). Así que la motivación para apoyarlo es incluso menor de lo que era originalmente.


La respuesta breve y precisa es simplemente "porque eso es lo que decidió Bjarne".

Aunque los argumentos sobre qué operandos deben evaluarse y en qué secuencia dan una descripción técnicamente precisa de lo que sucede, hacen poco (en realidad, nada) para explicar por qué este operador en particular no puede ser sobrecargado.

En particular, los mismos argumentos básicos se aplicarían igualmente bien a otros operadores como operator && y operator|| . En la versión incorporada de cada uno de estos operadores, se evalúa el operando izquierdo, luego si y solo si eso produce 1 para && o 0 para || , se evalúa el operando correcto. Del mismo modo, el operador de coma (incorporado) evalúa su operando izquierdo, luego su operando derecho.

En una versión sobrecargada de cualquiera de estos operadores, ambos operandos siempre se evalúan (en una secuencia no especificada). Como tales, son esencialmente idénticos a un operador ternario sobrecargado a este respecto. Todos pierden las mismas garantías sobre qué operandos se evalúan y en qué orden.

En cuanto a por qué Bjarne tomó esa decisión: puedo ver algunas posibilidades. Una es que, aunque técnicamente es un operador, el operador ternario se dedica principalmente al control de flujo, por lo que la sobrecarga sería más como una sobrecarga if es más que una sobrecarga para la mayoría de los demás operadores.

Otra posibilidad sería que fuera sintácticamente feo, requiriendo que el analizador trate con algo como operator?: , que requiere definir ?: Como un token, etc. - todos requieren cambios bastante serios en la gramática C. Al menos en mi opinión, este argumento parece bastante débil, ya que C ++ ya requiere un analizador mucho más complejo que C, y este cambio realmente sería mucho más pequeño que muchos otros cambios que se han realizado.

Quizás el argumento más fuerte de todos es simplemente que no parecía que lograría mucho. Dado que se dedica principalmente al control de flujo, es poco probable que el cambio de lo que haga para algunos tipos de operandos logre algo muy útil.


Por la misma razón por la que realmente no debería (aunque puede) sobrecargar && o || operadores: si lo hace, se desactivaría el cortocircuito en esos operadores (evaluar solo la parte necesaria y no todo), lo que puede llevar a complicaciones graves.


Uno de los principios del operador ternario es que la expresión verdadera / falsa solo se evalúa en función de la verdad o falsedad de la expresión condicional.

cond ? expr1 : expr2

En este ejemplo, expr1 solo se evalúa si cond es verdadero, mientras que expr2 solo se evalúa si cond es falso. Teniendo esto en cuenta, veamos cómo sería una firma para la sobrecarga ternaria (utilizando tipos fijos aquí en lugar de una plantilla para simplificar)

Result operator?(const Result& left, const Result& right) { ... }

Esta firma simplemente no es legal porque viola la semántica exacta que describí. Para llamar a este método, el lenguaje tendría que evaluar tanto expr1 como expr2 por lo que ya no se evalúan condicionalmente. Para apoyar el ternario, el operador tendría que

  1. Tome una lambda para cada valor para que pueda producirlos a pedido. Sin embargo, esto necesariamente complicaría el código de llamada, ya que tendría que tomar en cuenta la semántica de llamada lambda donde no existe lógicamente lambda
  2. El operador ternario tendría que devolver un valor para indicar si el compilador debería usar expr1 o expr2

EDITAR

Algunos pueden argumentar que la falta de cortocircuitos en este escenario está bien. La razón es que C ++ ya le permite violar el cortocircuito en sobrecargas de operadores con || y &&

Result operator&&(const Result& left, const Result& right) { ... }

Aunque todavía encuentro este comportamiento desconcertante incluso para C ++.


si pudiera anular el operador ternario, tendría que escribir algo como esto:

xxx operator ?: ( bool condition, xxx trueVal, xxx falseVal );

Para llamar a su reemplazo, el compilador tendría que calcular el valor de trueVal y falseVal . No es así como funciona el operador ternario incorporado, solo calcula uno de esos valores, por lo que puede escribir cosas como:

return p == NULL ? 23 : p->value;

sin preocuparse por dirigir a través de un puntero NULL.