c++ - and - operator in c
¿Hay un "y" lógico no cortocircuitado en C++? (7)
tl; dr: ¿Existe un AND no lógico de corto circuito en C ++ (similar a &&)?
Tengo 2 funciones a las que quiero llamar, y uso los valores de retorno para calcular el valor de retorno de una tercera función compuesta. El problema es que siempre quiero que ambas funciones evalúen (ya que generan información de registro sobre el estado del sistema)
ES DECIR:
bool Func1(int x, int y){
if( x > y){
cout << "ERROR- X > Y" << endl;
}
}
bool Func2(int z, int q){
if( q * 3 < z){
cout << "ERROR- Q < Z/3" << endl;
}
}
bool Func3(int x, int y, int z, int q){
return ( Func1(x, y) && Func2(z, q) );
}
Por supuesto, los condicionales no son tan simples en las funciones, y sí, me doy cuenta de que podría usar variables temporales para almacenar los rendimientos de las dos funciones y luego hacer la lógica de "cortocircuito" en las variables temporales, pero Me preguntaba si existía una solución de lenguaje "elegante" para mantener el retorno de una línea en Func3 mientras se siguen recibiendo los mensajes de registro de ambas funciones.
Resumen de las respuestas:
Los operadores "bitwise" | y & puede usarse para obtener el efecto, pero solo si el tipo de retorno es bool. No encontré ninguna mención de esto en la especificación ANSI C ++. Por lo que puedo decir, esto funciona porque el "bool" se convierte en un int (verdadero = 1, falso = 0), y luego se usa el operador a nivel de bits, luego se vuelve a convertir en un bool.
Los Operadores " +
" y " *
" también se pueden usar. Esto no se menciona en la especificación ANSI C ++, pero probablemente funcione debido a la misma razón que la anterior. " +
" give "o" porque true se convierte a 1, y luego cualquier cosa que no sea 0 se convierte de nuevo a true. " *
" funciona para "y" porque 1 (verdadero) * 0 (falso) == 0 (falso) y 1 (verdadero) * 1 (verdadero) == 1 (verdadero)
Ambos parecen depender de la conversión de tipos implícita a entero y luego a bool. Es probable que ambas cosas arruinen a quien intente mantener el código.
Otras respuestas se reducen a "solo usar temporales" o "implementa las tuyas", que no era la pregunta. El objetivo era ver si ya existía un operador implementado en el estándar C ++ para hacerlo.
y sí, me doy cuenta de que podría usar variables temporales para almacenar los rendimientos de las dos funciones y luego hacer la lógica de "cortocircuito" en las variables temporales, pero me preguntaba si había una solución de lenguaje "elegante" para mantener la retorno de una línea en Func3 mientras sigue recibiendo los mensajes de registro de ambas funciones.
Esa sería la solución "elegante" :). Confiar en los efectos secundarios del orden de evaluación estaría lejos de ser elegante, propenso a errores y difícil de entender para el próximo desarrollador que se adentra en su proyecto. Confiar en los efectos secundarios del curso contrasta con algo como el siguiente fragmento de código, que es un caso de uso completamente lógico y válido para confiar solo en el orden de evaluación:
if ( obj != NULL && obj->foo == blah ) { /* do stuff */ }
El operador &
realiza operaciones lógicas "y" para operandos bool
y no está en cortocircuito.
No es un punto de secuencia. No se puede confiar en el orden de evaluación de los operandos. Sin embargo, está garantizado que ambos operandos son evaluados.
No recomiendo hacer esto. Usar variables temporales es una mejor solución. No sacrifique la legibilidad por "código inteligente".
Puedes escribir trivialmente el tuyo propio.
bool LongCircuitAnd( bool term1, bool term2 ) { return term1 && term2; }
bool Func3(int x, int y, int z, int q){
return LongCircuitAnd( Func1(x,y), Func2(z,q) );
Y si quieres ser muy elegante, ¡incluso podrías incluirlo en línea!
Está bien, está bien, si realmente no quieres la terrible sobrecarga de llamar a una función.
bool Func3(int x, int y, int z, int q){
return ((int)Func1(x,y)) * ((int)Func2(z,q));
Pero no lo considero elegante. Es concebible que un compilador demasiado inteligente pueda provocar un cortocircuito en este ...
Sí, hay operadores integrados para hacer esto. +
hace un no cortocircuito O y *
hace un AND.
☺
#include <iostream>
using namespace std;
void print(bool b)
{
cout << boolalpha << b << endl;
}
int main()
{
print(true + false);
print(true * false);
}
Salida:
cierto
falso
Sí. Las versiones sobrecargadas de operator&&
y operator||
no cortocircuite: evalúan ambos operandos incluso si el operando de la izquierda "determina" el resultado ... ( Source )
Dicho esto, no sobrecargue el operator&&
o el operator||
. Sea amable con sus programadores de mantenimiento que verán &&
o ||
y supongamos que hacen corto circuito.
Si desea usar las variables temporales, pero mantener el retorno a una sola declaración, puede usar el operador de coma:
return (b1=Func1()), (b2=Func2()), (b1&&b2);
El operador de coma fuerza un punto de secuencia, por lo que cada uno evalúa su operando izquierdo, descarta el resultado y luego evalúa su operando derecho.
Otra posibilidad, pero una que recomendaría en contra, sería que las dos funciones devuelvan un tipo que sobrecargue al operador ''&&''. Dado que un operador sobrecargado invoca una función, siempre evalúa ambos operandos, incluso en los casos (como &&) donde el operador integrado no lo hace, por lo general eso es un problema, pero en este caso es exactamente lo que quiere:
class mybool {
bool value;
public:
bool operator&&(mybool const &other) const {
return value && other.value;
}
};
mybool Func1(int, int);
mybool Func2(int, int);
bool Func3(int x, int y, int z, int q) {
return Func1(x, y) && Func2(z,q);
}
Si bien esto funciona, me parece que es un poco demasiado "inteligente", algo que no sería del todo obvio para la mayoría de los lectores. Un nombre diferente para mybool
podría ayudar, pero de antemano no puedo pensar en uno que refleje la intención muy bien sin llegar a ser tan detallado que sería una pérdida neta.
Un operador no estándar casi universal pero a menudo no documentado se introdujo exactamente para este propósito, fue pionero en GCC junto con x ?: y
(x si no es cero más y), y el ahora lamentablemente eliminado >?
y <?
operadores min / max y sus formularios de asignación compuestos (consulte http://gcc.gnu.org/onlinedocs/gcc/Deprecated-Features.html ). Lamentablemente, con &
&&
ya en uso, parecen haber estado raspando el fondo del barril para encontrar una secuencia de caracteres adecuada, pero esa es solo mi opinión: agradecería cualquier explicación histórica de por qué se podría haber elegido.
Entonces, aunque actualmente no es tan conocido como muchos otros operadores, el >!
la mayoría de los compiladores de C y C ++ (incluido GCC e incluso MSVC ++) agregaron un operador (apropiadamente pero aburridamente llamado "circuito largo y", pero coloquialmente "nudo más grande" por los que saben) para satisfacer este requisito:
bool f1() { ... }
bool f2() { ... }
...
bool f3() { return f1() >! f2(); }
Tómalo para dar una vuelta ;-).