Comparación de C++20: advertencia sobre el operador inverso ambiguo

4 minutos de lectura

Considere este ejemplo válido de C++17:

struct A {
   bool operator==(const A&);
};


int main() {
   return A{} == A{};
}

Cuando compilado en clang con -std=c++20 da:

<source>:7:15: warning: ISO C++20 considers use of overloaded operator '==' (with operand types 'A' and 'A') to be ambiguous despite there being a unique best viable function [-Wambiguous-reversed-operator]

   return A{} == A{};

          ~~~ ^  ~~~

<source>:2:9: note: ambiguity is between a regular call to this operator and a call with the argument order reversed

   bool operator==(const A&);

¿Significa esta advertencia que C++20 no permite el uso de un operador de comparación típico para comparar dos objetos del mismo tipo? ¿Cuál es la alternativa correcta? ¿Se espera que la situación cambie en futuros borradores?

  • Dejaré los detalles a un abogado de idiomas, pero haciendo la función const debe dejar que la advertencia se evapore. creo que existe el aviso, ya que invocas operator== en un temporal.

    – aep

    25 de febrero de 2020 a las 2:45

  • @aep Es cierto que la advertencia desaparece agregando constpero no quitando el temporal (A a, b; a == b). Gracias, supongo que debe estar relacionado con un lado de la == siendo const pero no el otro.

    – Falta

    25 de febrero de 2020 a las 3:03


  • No hay más cambios para C++20 (excepto los que aún se están fusionando desde la última reunión para esa versión).

    – Davis arenque

    25 de febrero de 2020 a las 3:13

  • Lo juro, la mitad de la razón por la que prefiero seguir la pauta de “usar sobrecargas de no miembros” es que es muy fácil olvidarse de declarar la función miembro en sí constdonde la función que no es miembro solo necesita recordar declarar los argumentos const.

    – ShadowRanger

    25 de febrero de 2020 a las 3:25


¿Significa esta advertencia que C++20 no permite el uso de un operador de comparación típico para comparar dos objetos del mismo tipo? ¿Cuál es la alternativa correcta? ¿Se espera que la situación cambie en futuros borradores?

Este no es realmente un operador de comparación típico, ya es un poco incorrecto, ya que solo permite un const objeto en un lado (su tipo A no satisfaría el nuevo equality_comparable concepto tampoco, incluso sin cambios de idioma).

Tienes que escribirlo de esta manera:

struct A {
   bool operator==(const A&) const;
//                          ^^^^^^
};

Esta es la regla final para C++20.


El problema específico es que en C++20, los operadores de comparación agregan una nueva noción de candidatos reescritos e invertidos. Así que busca la expresión a == b también terminará haciendo coincidir operadores como b == a. En el caso típico, esto significa que tienes que escribir menos operadores, ya que sabemos que la igualdad es conmutativa.

Pero si tiene un desajuste constante, lo que sucede es que termina con estos dos candidatos:

bool operator==(/* this*/ A&, A const&); // member function
bool operator==(A const&, /* this*/ A&); // reversed member function

Con dos argumentos de tipo A. El primer candidato es mejor en el primer argumento y el segundo candidato es mejor en el segundo argumento. Ninguno de los candidatos es mejor que el otro, por lo tanto, ambiguo.

Es una regla general de resolución de sobrecarga que cada tipo de argumento debe ser por separado al menos tan cerca del tipo de parámetro de una función seleccionada como del tipo de parámetro de cualquier otra:

struct A {A(int);};
void f(long,int);   // #1
void f(int,A);      // #2
void g() {f(0,0);}  // error: ambiguous

La conversión mucho peor para el segundo argumento para el n. ° 2 no compensa el intlong conversión en el primer argumento.

En C++20, se agregaron varias reglas de reescritura para obviar la necesidad de escribir tantas sobrecargas de operadores de comparación casi idénticas. Mientras que las ambigüedades triviales entre los “candidatos invertidos” escritos a mano y los generados por compiladores idénticos son manejados por desempate reglas que prefieren funciones reales, eso (nuevamente) no es suficiente para compensar una conversión peor para cualquier argumento.

Los operadores de comparación escritos cuidadosamente de acuerdo con las prácticas aceptadas (C ++ 17) rara vez entrarán en conflicto con esto, pero cuestionable firmas como esta (con asimétrica const) puede muy bien ser problemático (en nuevas formas). Esperemos que se encuentren más errores de los causados ​​por esta extensión.

  • @Barry: Bueno, (Clang) degradarlo a una advertencia le da a la gente otra forma de convertir “lentamente” (-Wno-error=ambiguous-reversed-operator además de algún tipo de modo C ++ 17 con visión de futuro).

    – Davis arenque

    25 de febrero de 2020 a las 3:52

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad