libreria ejemplos c++ c++11 language-lawyer cmath

libreria - math.h c++ ejemplos



¿Está std:: abs(0u) mal formado? (1)

Parece que libstdc++ es correcto, esto no está mal formado, aunque veremos que hay algunas dudas sobre si esto es un defecto en el problema activo de LWG 2192 .

El borrador de la sección estándar C ++ 11 26.8 [c.math] párrafo 11 dice:

Además, habrá sobrecargas adicionales suficientes para garantizar:

e incluye el siguiente artículo:

  1. De lo contrario, si cualquier argumento correspondiente a un parámetro doble tiene un tipo double o un entero, todos los argumentos correspondientes a los parámetros dobles se convierten efectivamente en dobles.

y podemos ver que libstdc++ hecho provee para este caso:

template<typename _Tp> inline typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, double>::__type abs(_Tp __x) { return __builtin_fabs(__x); }

También existe un error de gcc Std :: abs (long long) recurre a std :: abs (double) si llabs está ausente , lo que cuestiona si esta implementación es correcta y una respuesta dice:

[...] está bien según el Estándar, se supone que cualquier número entero se convertirá incondicionalmente en el doble. [...]

El informe de error eventualmente lleva a la emisión activa LWG 2192: Validez y tipo de devolución de std :: abs (0u) no está claro si se archiva, lo que dice, entre otras cosas:

  1. En C ++ 11, la regla adicional de "sobrecarga suficiente" de 26.8 [c.math] p11 (ver también LWG 2086) puede leerse para ser aplicable a las sobrecargas std :: abs () también, lo que puede llevar a la siguiente posibles conclusiones:

El programa

#include <type_traits> #include <cmath> static_assert(std::is_same<decltype(std::abs(0u)), double>(), "Oops"); int main() { std::abs(0u); // Calls std::abs(double) }

debe estar bien formado, debido a la subtrama 2 ("[..] o un tipo entero [..]") de 26.8 [c.math] p11 (Tenga en cuenta que la resolución actual de LWG 2086 no arregla este problema).

  1. Cualquier unidad de traducción que incluye ambos y podría estar mal formada debido a dos requisitos contradictorios para el tipo de devolución de la sobrecarga std :: abs (int).

Me parece que al menos el segundo resultado no es intencionado, personalmente creo que ambos son desafortunados. También debe señalarse que la regla correspondiente a la "función de tipo genérico" se estableció a partir de C99 / C1x en 7.25 p2 + 3 está restringido a las funciones de punto flotante desde y, por lo que no se puede aplicar a las funciones de abs (¡sino a las funciones de fabs!).

La pregunta es si esto también se aplicaba a los abs . Esto podría ser un defecto ya que no parece haber una manera de interpretar la redacción actual para excluir abs .

Así que la redacción actual indica que libstdc++ es conforme, no está claro por qué libc++ ha elegido su implementación actual tal como es. No puedo encontrar informes de errores ni discusiones que involucren este tema y el tema LWG no menciona implementaciones divergentes.

La solución propuesta haría std::abs(0u) mal formado:

Si se llama a abs () con un argumento de tipo integral sin signo que no se puede convertir a int por promoción integral ([conv.prom]), el programa está mal formado. [Nota: los argumentos que se pueden promocionar a int se permiten para compatibilidad con C. - nota final]

Mientras que algunos pueden cuestionar la noción de usar abs con un tipo sin firmar, Howard Hinnant señala en el informe que al usar plantillas, tales consecuencias pueden no ser evidentes y proporcionan un ejemplo:

[...] especialmente en C ++, donde tenemos plantillas, y los tipos involucrados no siempre son evidentes para el programador en el momento del diseño. Por ejemplo, considere:

template <class Int> Int analyze(Int x, Int y) { // ... if (std::abs(x - y) < threshold) { // ... } // ... }

Dado el siguiente programa:

#include <cmath> int main() { std::abs(0u) ; }

gcc y clang están en desacuerdo sobre si esto está mal formado. Usando gcc con libstdc++ el código se genera sin error o advertencia ( verlo en vivo ), mientras usa clang con libc++ genera el siguiente error ( ver en vivo ):

error: call to ''abs'' is ambiguous std::abs(0u) ; ^~~~~~~~

¿Qué resultado es correcto? ¿ abs(0u) debe ser ambiguo o no?

MSalters señala una pregunta relacionada interesante: Versión de plantilla de std :: abs .