Rompiendo el cambio en C ++ 20 o regresión en el sonido metálico-tronco / gcc-maletero cuando la sobrecarga de comparación de igualdad con el valor de retorno no booleano?

ChTZ:

El siguiente código compila bien con el sonido metálico-tronco en C ++ 17 modo, pero se rompe en el modo C ++ 2a (próxima c ++ 20):

// Meta struct describing the result of a comparison
struct Meta {};

struct Foo {
    Meta operator==(const Foo&) {return Meta{};}
    Meta operator!=(const Foo&) {return Meta{};}
};

int main()
{
    Meta res = (Foo{} != Foo{});
}

También compila bien con gcc-tronco o sonido metálico-9.0.0: https://godbolt.org/z/8GGT78

El error con el sonido metálico-tronco y -std=c++2a:

<source>:12:19: error: use of overloaded operator '!=' is ambiguous (with operand types 'Foo' and 'Foo')
    Meta res = (f != g);
                ~ ^  ~
<source>:6:10: note: candidate function
    Meta operator!=(const Foo&) {return Meta{};}
         ^
<source>:5:10: note: candidate function
    Meta operator==(const Foo&) {return Meta{};}
         ^
<source>:5:10: note: candidate function (with reversed parameter order)

Yo entiendo que el C ++ 20 hará posible sólo a la sobrecarga operator==y el compilador generará de forma automática operator!=mediante la negación del resultado de operator==. Por lo que yo entiendo, esto sólo funciona siempre y cuando el tipo de retorno es bool.

La fuente del problema es que en Eigen declaramos un conjunto de operadores ==, !=, <, ... entre Arrayobjetos o Arrayy escalares, que devuelven (una expresión de) una matriz de bool(que luego se puede acceder elemento a elemento, o utilizado de otra manera ). P.ej,

#include <Eigen/Core>
int main()
{
  Eigen::ArrayXd a(10);
  a.setRandom();
  return (a != 0.0).any();
}

En contraste con el ejemplo anterior esto incluso falla con gcc-tronco: https://godbolt.org/z/RWktKs . Todavía no he conseguido reducir a un ejemplo no Eigen, que falla tanto en sonido metálico-tronco y gcc-tronco (el ejemplo en la parte superior es bastante simplificada).

Informar de un problema relacionado: https://gitlab.com/libeigen/eigen/issues/1833

Mi pregunta fue: ¿Esto es en realidad un cambio importante en C ++ 20 (y hay una posibilidad de sobrecargar los operadores de comparación para volver metaobjetos), o es más probable que una regresión en sonido metálico / gcc?

TC:

La cuestión Eigen parece reducir a lo siguiente:

using Scalar = double;

template<class Derived>
struct Base {
    friend inline int operator==(const Scalar&, const Derived&) { return 1; }
    int operator!=(const Scalar&) const;
};

struct X : Base<X> {};

int main() {
    X{} != 0.0;
}

Los dos candidatos para la expresión son

  1. el candidato reescrito desde operator==(const Scalar&, const Derived&)
  2. Base<X>::operator!=(const Scalar&) const

Per [over.match.funcs] / 4 , como operator!=no fue importada en el alcance de Xpor un -declaración usando , el tipo de parámetro de objeto implícito para # 2 es const Base<X>&. Como resultado, # 1 tiene una secuencia de conversión mejor implícita para que el argumento (coincidencia exacta, en lugar de deriva-a-base conversión). Selección # 1, entonces el programa hace mal formada.

Posibles soluciones:

  • Añadir using Base::operator!=;a Derived, o
  • Cambiar el operator==a tomar un const Base&lugar de una const Derived&.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=369796&siteId=1
Recomendado
Clasificación