Otros operadores
![]() |
Esta página se ha traducido por ordenador/computador/computadora de la versión en inglés de la Wiki usando Google Translate.
La traducción puede contener errores y palabras aparatosas/incorrectas. Planea sobre el texto para ver la versión original. Puedes ayudar a corregir los errores y mejorar la traducción. Para instrucciones haz clic aquí. |
Nombre operador | Sintaxis | Sobrecargable | Ejemplos de prototipos (para class T) | |
---|---|---|---|---|
Dentro de definición de clase | Fuera de definición de clase | |||
llamada a función | a(a1, a2)
|
Sí | R T::operator()(Arg1 &a1, Arg2 &a2, ... ); | N/A |
coma | a, b
|
Sí | T2& T::operator,(T2 &b); | T2& operator,(const T &a, T2 &b); |
operador condicional | a ? b : c
|
No | N/A | N/A |
Contenido |
[editar] Explicación
El operador llamada a función provee semántica de función para cualquier objeto.
El operador condicional (coloquialmente conocido como condicional ternario) comprueba el valor lógico de la primera expresión y, dependiendo del valor resultante, evalúa y devuelve la segunda o tercera expresión.
[editar] Operador de llamada a función integrado
Las expresiones de llamada a función tienen la forma
E ( A1, A2, A3,... )
|
|||||||||
donde
- E es una expresión que nombra a la función
- A1, A2, A3,... es una lista de expresiones arbitrarias que puede estar vacía, excepto el operador coma no está permitido en el nivel superior para evitar la ambigüedad.
La expresión que da nombre a la función puede ser
El nombre de función (o miembro) especificado por E
se puede sobrecargar, las reglas de resolución de sobrecarga se usan para decidir cual de ellas se llama.
Si E
especifica una función miembro, podría ser virtual, en cuyo caso se llamará a la sobreescritura final de esa función, usando el manejador dinámico en tiempo de ejecución.
Para llamar a la función,
La expresión |
(hasta C++17) |
La expresión |
(desde C++17) |
Cada parámetro de la función se inicializa con su argumento correspondiente después de la conversión implícita si es necesaria. Si no está el argumento correspondiente, se usa el argumento por defecto que corresponde, y si no hay, el programa está mal formado. Si se realiza la llamada a una función miembro, entonces el puntero this al objeto actual se convierte como si fuera conversión explícita al puntero que espera la función. La inicialización y destrucción de cada parámetro ocurre en el contexto del llamador, lo que significa que, por ejemplo, que si el constructor de un parámetro lanza una excepción, el capturador de excepción definido dentro de la función, incluso para un bloque función-try, no se considera. Si la función es una función variable (número variable de argumentos), se aplica las promociones de argumentos por defecto a todos los argumentos coincidentes con el parámetro de puntos suspensivos. La implementación define si el tiempo de vida de un parámetro finaliza cuando la función en el que se define retorna o al final de la expresión completa que lo contiene.
El tipo devuelto por una expresión de llamada a función es el tipo de retorno de la función seleccionada, seleccionado mediante enlace estático (ignorando la palabra reservada virtual
), incluso si la función sobrecargada que en realidad se llama devuelve un tipo diferente. Esto permite a las funciones sobrecargadas devolver punteros o referencias a clases que son derivadas del tipo devuelto por la función base, por ejemplo, C++ soporta tipos de retorno covariantes. Si E
especifica un destructor, el tipo devuelto es void.
Cuando un objeto de tipo clase X se pasa o es devuelta por una función, si cada constructor copia, constructor de movimiento, y destructor de X es trivial o eliminado, y X tiene al menos un constructor de copia o movimiento no eliminado, se permite a las implementaciones crear un objeto temporal para contener el parámetro de función u objeto de resultado. El objeto temporal se construye con el argumento de la función o el valor devuelto, respectivamente, y el parámetro o el objeto devuelto de la función se inicializa como si se usara el constructor trivial no eliminado para copiar el temporal (incluso si ese constructor es inaccesible o no se selecciona por resolución de sobrecarga para realizar una copia o movimiento de objeto). Esto permite que objetos de tipo clases pequeños, como std::complex o |
(desde C++17) |
La categoría de valor de una expresión de llamada a función es lvalue si la función devuelve una referencia lvalue o una referencia rvalue a función, es un xvalue si la función devuelve una referencia rvalue a objeto, y es un prvalue en otro caso. Si la expresión de llamada a función es un prvalue de tipo objeto, debe tener tipo completo excepto {rev inl|since=c++17|cuando el prvalue no se materializa, así como}} cuando se usa como operando de decltype (o como el operando derecho de una expresión operador coma integrado esto es el oprando de decltype
).
La expresión de llamada a función es similar en sintaxis a una inicialización de valor T(), a una expresión de conversión estilo función T(A1), y a la inicialización directa de un temporal T(A1, A2, A3, ...), donde T
es el nombre del tipo.
#include <cstdio> struct S { int f1(double d) { return printf("%f \n", d); // llamada a función de número de argumentos variable } int f2() { return f1(7); // llamada a función miembro, igual que this->f1() // el argumento entero se convierte a double } }; void f() { puts("función llamada"); // llamada a función } int main() { f(); // llamada a función S s; s.f2(); // llamada a función miembro }
Salida:
función llamada 7.000000
[editar] Operador coma integrado
Las expresiones del operador coma tienen la forma
E1 , E2
|
|||||||||
En una expresión coma E1, E2, se evalúa la expresión E1
, su resultado se descarta (aunque si es de tipo clase, no será destruido hasta el final de la expresión completa que la contiene), y sus efectos secundarios se completan antes del comienzo de la evaluación de la expresión E2
(tenga en cuenta que el operator,
definido por usuario no puede garantizar la secuencia) (hasta C++17).
El tipo, el valor y la categoría de valor del resultado de la expresión coma son exactamente el tipo, el valor y la categoría de valor del segundo operando, E2
. Si E2
es una expresión (desde C++17) temporal, el resultado de la expresión es esa expresión (desde C++17) temporal. Si E2
es un campo de bits, el resultado es un campo de bits.
La coma en varias listas separadas por coma, como el listado de argumentos de una función (f(a, b, c)) y listado de inicialización int a[] = {1,2,3}, no es el operador coma. Si se necesita usar el operador coma en estos contextos, tiene que estar entre paréntesis: f(a, (n++, n+b), c)
Salida:
n = 2 m = 7
[editar] Operador condicional
Las expresiones del operador condicional tienen la forma
E1 ? E2 : E3
|
|||||||||
Se evalúa el primer operando del operador condicional y se convierte contextualmente a bool. Después de que completen la evaluación de valor y todos los efectos secundarios del primer operando, si el resultado es true, se evalúa el segundo operando. Si el resultado es false, se evalúa el tercer operando.
El tipo y categoría de valor de la expresión condicional E1 ? E2 : E3 se determina de acuerdo con las siguientes reglas:
E2
o E3
tienen tipo void, entonces una de las siguientes condiciones debe ser verdadera, o el programa está mal formado:E2
o E3
(pero no los dos) es una (que puede estar entre paréntesis) expresión throw. El resultado del operador condicional tiene el tipo y la categoría de valor de la otra expresión. Si la otra expresión es un campo de bits, el resultado es un campo de bits. Dicho operador condicional se usaba comúnmente en C ++ 11 constexpr programación antes de C++14.
std::string str = 2+2==4 ? "ok" : throw std::logic_error("2+2 != 4");
E2
y E3
son de tipo void (incluyendo el caso cuando los dos son expresiones throw). El resultado es un prvalue de tipo void.
2+2==4 ? throw 123 : throw 456;
2) En otro caso, si E2 o E3 son campos de bits glvalue de la misma categoría de valor y de tipos cv1 T y cv2 T, respectivamente, se considera que son de tipo cv T para el resto de esta sección, donde cv es la unión de cv1 y cv2.
|
(desde C++14) |
E2
y E3
tienen tipos diferentes, al menos uno es un tipo clase (con posibilidad de ser calificado constante/volátil), o ambos son glvalues de la misma categoría de valor y tienen el mismo tipo excepto la calificación constante/volátil, entonces se intenta formar una secuencia de conversión implícita ignorando el acceso a miembro, si un operando es un campo de bits o si se elimina una función de conversión (desde C++14). de cada uno de los operandos al tipo destino determinado por el otro operando, como se describe a continuación. Un opernado (denominado X
) de tipo TX
se puede convertir al tipo destino de otro operando (denominado Y
) de tipo TY
como sigue:Y
es un lvalue, el tipo destino es TY&
, y la referencia debe enlazar directamente a un lvalue;Y
es un xvalue, el tipo destino es TY&&
, y la referencia debe enlazar directamente;Y
es un prvalue, o si no se pueden formar las secuencias de conversión anteriores y al menos una de TX
y TY
es un tipo clase (que puede se calificado constante/volátil),TX
y TY
son del mismo tipo clase (ignorando la calificación constante/volátil) y TY
es al menos tan calificado constante/volátil como TX
, el tipo destino es TY
,TY
es clase base de TX
, el tipo destino es TY
con los calificadores constante/volátil de TX
struct A {}; struct B : A {}; using T = const B; A a = true ? A() : T(); // Y = A(), TY = A, X = T(), TX = const B. Destino = const A
Y
después de aplicar las conversiones estándar de lvalue a rvalue, matriz a puntero, y función a puntero E2
y E3
son glvalues del mismo tipo y categoría de valor, entonces el resultado tiene el mismo tipo y categoría de valor, y es un campo de bits si al menos uno, E2
o E3
es un campo de bits.E2
y E3
no tienen el mismo tipo, y cualquiera de los dos tiene un tipo clase (que puede estar calificado constante/volátil), a continuación se realiza la resolución de sobrecarga utilizando los candidatos integrados para intentar convertir los operandos a tipos integrados. Si la resolución de sobrecarga falla, el programa está mal formado. En otro caso, se aplican las conversiones seleccionadas y se usan los operandos convertidos en lugar de los originales para el paso 6.E2
y E3
tienen el mismo tipo, el resultado es un prvalue de ese tipo que designa un objeto temporal (hasta C++17)cuyo objeto resultado es (desde C++17) copia inicializada desde cualquier operando que se seleccionó después de evaluar E1
.E2
y E3
tienen tipo aritmético o enumerado: las conversiones aritméticas usuales se aplican para llegar a un tipo común, y este tipo es el resultado.E2
y E3
son punteros, o uno es un puntero y el otro la constante puntero nulo, entonces se aplican conversiones de puntero y calificación para llegar a un tipo común, y este tipo es el resultado.E2
y E3
son punteros a miembro, o uno es un puntero a miembro y el otro una constante puntero nulo, entonces se aplican las conversiones de puntero a miembro y calificación para llegar a un tipo común, y este tipo es el resultado.E2
y E3
son constantes puntero nulo, y al menos uno de ellos es de tipo std::nullptr_t, entonces el tipo del resultado es std::nullptr_t
.Para cada par de tipos aritméticos promocionados L y R y para cada tipo P, donde P es un puntero, puntero a miembro, o tipo enumerado con ámbito, los siguientes modelos de función participan en la resolución de sobrecarga realizada en el paso 5 de las reglas anteriores:
LR operator?:(bool, L, R ); |
||
P operator?:(bool, P, P ); |
||
Donde LR es el resultado de las conversiones aritméticas usuales realizadas sobre L
y R
. No se puede sobre cargar el operador “?:”, esos modelos de función solamente existen con el propósito de resolución de sobrecarga.
El tipo de retorno de un operador condicional también es accesible como la característica del tipo binario std::common_type.
#include <string> #include <iostream> struct Node { Node* next; int data; // constructor copia de copia profunda Node(const Node& other) : next(other.next ? new Node(*other.next) : NULL) , data(other.data) {} Node(int d) : next(NULL), data(d) {} ~Node() { delete next ; } }; int main() { // ejemplo simple de rvalue int n = 1>2 ? 10 : 11; // 1>2 es falso, por lo que n = 11 // ejemplo simple de lvalue int m = 10; (n == m ? n : m) = 7; // n == m es falso, entonces m = 7 std::cout << "n = " << n << "\nm = " << m; // mostrar resultado }
Salida:
n = 11 m = 7
[editar] Biblioteca estándar
Muchas clases en la biblioteca estándar sobrecargan el operator()
para ser usado como objetos función.
Elimina el objeto o array. (función miembro pública de std::default_delete )
| |
Devuelve la suma de dos argumentos. (función miembro pública de std::plus )
| |
devuelve la diferencia entre dos argumentos (función miembro pública de std::minus )
| |
devuelve el producto de dos argumentos (función miembro pública de std::multiplies )
| |
devuelve el resultado de la división del primer argumento por el segundo argumento (función miembro pública de std::divides )
| |
devuelve el resto de la división del primer argumento por el segundo argumento (función miembro pública de std::modulus )
| |
devuelve la negación del argumento (función miembro pública de std::negate )
| |
Comprueba si los argumentos son iguales (función miembro pública de std::equal_to )
| |
Comprueba si los argumentos no son iguales (función miembro pública de std::not_equal_to )
| |
Comprueba si el primer argumento es mayor que el segundo (función miembro pública de std::greater )
| |
comprueba si el primer argumento es menor que el segundo (función miembro pública de std::less )
| |
Comprueba si el primer argumento es mayor o igual que el segundo (función miembro pública de std::greater_equal )
| |
Comprueba si el primer argumento es menor o igual que la segunda (función miembro pública de std::less_equal )
| |
devuelve el AND lógico de los dos argumentos (función miembro pública de std::logical_and )
| |
devuelve el OR lógico de los dos argumentos (función miembro pública de std::logical_or )
| |
devuelve el NO lógico del argumento (función miembro pública de std::logical_not )
| |
devuelve el resultado de AND entre bits de los dos argumentos (función miembro pública de std::bit_and )
| |
Devuelve el resultado del operador OR entre bits de dos argumentos (función miembro pública de std::bit_or )
| |
devuelve el resultado de XOR de bits de dos argumentos (función miembro pública de std::bit_xor )
| |
devuelve el complemento lógico del resultado de una llamada al predicado almacenado (función miembro pública de std::unary_negate )
| |
devuelve el complemento lógico del resultado de una llamada al predicado almacenado (función miembro pública de std::binary_negate )
| |
llama a la función almacenada (función miembro pública de std::reference_wrapper )
| |
Invoca el destino. (función miembro pública de std::function )
| |
Compara lexicográficamente dos cadenas utilizando la faceta de intercalación de esta configuración regional. (función miembro pública de std::locale )
| |
Compara dos valores de tipo value_type . (función miembro pública de std::map<Key,T,Compare,Allocator>::value_compare )
| |
Compara dos valores de tipo value_type . (función miembro pública de std::multimap<Key,T,Compare,Allocator>::value_compare )
| |
Ejecuta la función. (función miembro pública de std::packaged_task )
| |
avanza el estado del motor de generación aleatorio y devuelve el valor generado (función miembro pública de std::linear_congruential_engine )
| |
genera el siguiente número aleatorio en la distribución (función miembro pública de std::uniform_int_distribution )
|
El operador coma no está sobrecargado por ninguna clase en la biblioteca estándar. La biblioteca boost usa operator,
en boost.assign, boost.spirit, y otras bibliotecas. La biblioteca de acceso a base de datos SOCI también sobrecarga operator,
.
[editar] Informe de defectos
Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.
ID | Aplicado a | Comportamiento según lo publicado | Comportamiento correcto |
---|---|---|---|
CWG 1550 | C++98 | No se permitía expresiones throw entre paréntesis en ?: si el otro operando no es void | se aceptan expresiones throw entre paréntesis |
CWG 1560 | C++98 | un operando void en ?: causaba una conversión lvalue a rvlaue innecesaria en el otro operando, resultando siempre un rvalue |
?: con void puede ser lvalue |
CWG 1932 | C++14 | faltaban campos de bits del mismo tipo en ?: | manejado por tipos subyacentes |
CWG 1895 | C++14 | no está claro si una función de conversión eliminada o inaccesible evita la conversión en ?:, y no se consideraba las conversiones desde la clase base a la clase derivada prvalue |
se maneja como si fuera una resolución de sobrecarga |
[editar] Ver también
Operadores comunes | ||||||
---|---|---|---|---|---|---|
Asignación | Incremento/decremento | Aritméticos | Lógicos | Comparación | Acceso a miembro | Otros |
a = b |
++a |
+a |
!a |
a == b |
a[b] |
a(...) |
Operadores especiales | ||||||
static_cast Convierte de un tipo a otro tipo relacionado |
Documentación de C para Otros operadores
|