equal - overload c++ operator
¿Por qué el estrechamiento no afecta la resolución de sobrecarga? (2)
Considera lo siguiente:
struct A {
A(float ) { }
A(int ) { }
};
int main() {
A{1.1}; // error: ambiguous
}
Esto no se compila con un error sobre una sobrecarga ambigua de A::A
Ambos candidatos se consideran viables, porque el requisito es simplemente :
Segundo, para que
F
sea una función viable, existirá para cada argumento una secuencia de conversión implícita (13.3.3.1) que convierte ese argumento en el parámetro correspondiente deF
Si bien hay una secuencia de conversión implícita de double
a int
, la sobrecarga A(int )
no es realmente viable (en el sentido estándar, no C ++), que implicaría una conversión de estrechamiento y, por lo tanto, estará mal formada.
¿Por qué las conversiones de reducción no se consideran en el proceso de determinar los candidatos viables? ¿Hay otras situaciones en las que una sobrecarga se considere ambigua a pesar de que solo un candidato sea viable?
Un problema radica en el hecho de que las conversiones de estrechamiento se pueden detectar no según los tipos.
Hay formas muy complejas de generar valores en tiempo de compilación en C ++.
Bloquear las conversiones de estrechamiento es una buena cosa. Hacer que la resolución de sobrecarga de C ++ sea aún más compleja de lo que ya es es algo malo.
Ignorar las reglas de conversión de reducción al determinar la resolución de sobrecarga (lo que hace que la resolución de sobrecarga se refiera únicamente a tipos), y luego generar un error cuando la sobrecarga seleccionada resulta en una conversión de reducción, mantiene la resolución de sobrecarga aún más compleja y agrega una manera de detectar y prevenir reduciendo las conversiones.
Dos ejemplos en los que solo un candidato es viable serían las funciones de plantilla que fallan "tarde", durante la creación de instancias y la inicialización de la lista de copias (donde se consideran constructores explicit
, pero si se eligen, se obtiene un error). De manera similar, tener esa resolución de sobrecarga de impacto haría la resolución de sobrecarga aún más compleja de lo que ya es.
Ahora, uno podría preguntarse, ¿por qué no doblar la conversión de la reducción simplemente en el sistema de tipos?
Hacer que la conversión del estrechamiento sea puramente basada en el tipo no sería viable. Dichos cambios podrían romper enormes cantidades de código "heredado" que el compilador podría probar como válido. El esfuerzo requerido para barrer una base de código es mucho más valioso cuando la mayoría de los errores son errores reales, y no la nueva versión del compilador es un imbécil.
unsigned char buff[]={0xff, 0x00, 0x1f};
esto fallaría en una conversión de reducción basada en tipo, ya que 0xff
es de tipo int
, y ese código es muy común.
Si tal código hubiera requerido una modificación inútil de los literales int
literales unsigned char
, las probabilidades son que el barrido hubiera terminado con que nosotros estableciéramos una bandera para decirle al compilador que se callara sobre el error estúpido.
El estrechamiento es algo que solo el compilador conoce para los tipos incorporados. Una conversión implícita definida por el usuario no se puede marcar como estrechamiento o no.
En primer lugar, no se debe permitir que las conversiones de reducción sean implícitas. (Desafortunadamente, era necesario para la compatibilidad con C. Esto se ha corregido de alguna manera con la inicialización
{}
prohíbe el estrechamiento de los tipos incorporados).
Teniendo en cuenta esto, tiene sentido que las reglas de sobrecarga no se molesten en mencionar este caso especial. Puede ser una conveniencia ocasional, pero no es tan valiosa. En mi opinión, es mejor en general tener menos factores involucrados en la resolución de sobrecargas y rechazar más cosas como ambiguas, lo que obliga al programador a resolver esas cosas explícitamente.
Además, doble para flotar es una conversión de estrechamiento cuando el doble no es una expresión constante o si el doble es demasiado grande.
#include <iostream>
#include <iomanip>
int main() {
double d{1.1};
float f{d};
std::cout << std::setprecision(100) << d << " " << f << ''/n'';
}
Esto normalmente producirá un error:
main.cpp:7:13: error: non-constant-expression cannot be narrowed from type ''double'' to ''float'' in initializer list [-Wc++11-narrowing]
float f{d};
^