c++ - smart - ¿Por qué tengo que usar el doble largo para los literales definidos por el usuario?
programar contratos inteligentes (4)
El siguiente literal definido por el usuario omite un error:
constexpr double operator "" _kg(double q)
{
return q*1000;
}
pero si se agrega long
el error desaparecerá y el código funcionará de la siguiente manera:
constexpr double operator "" _kg(long double q)
{
return q*1000;
}
el error es:
‘constexpr double operator""_kg(double)’ has invalid argument list
El problema solo es causado por el argumento y el tipo de retorno puede ser double
sin long
.
¿Por qué se necesita long
?
Solo se permiten las siguientes listas de parámetros en operadores literales:
- (const char *) (1)
- (sin firmar long long int) (2)
- (doble largo) (3)
- (char) (4)
- (wchar_t) (5)
- (char16_t) (6)
- (char32_t) (7)
- (const char *, std :: size_t) (8)
- (const wchar_t *, std :: size_t) (9)
(const char16_t *, std :: size_t) (10) (const char32_t *, std :: size_t) (11)
Los operadores literales con esta lista de parámetros son los operadores literales en bruto, que se utilizan como recursos alternativos para literales definidos por el usuario de enteros y puntos flotantes (ver arriba)
Los operadores literales con estas listas de parámetros son el operador literal de primera elección para literales enteros definidos por el usuario
Los operadores literales con estas listas de parámetros son el operador literal de primera elección para los literales de punto flotante definidos por el usuario
4-7. Los operadores literales con estas listas de parámetros son llamados por
literales de caracteres definidos por el usuario
8-11. Los operadores literales con estas listas de parámetros son llamados por literales de cadena definidos por el usuario
Los argumentos predeterminados no están permitidos. El enlace en lenguaje C no está permitido. Aparte de las restricciones anteriores, los operadores literales y las plantillas de operador literales son funciones normales (y plantillas de función), se pueden declarar en línea o constexpr, pueden tener enlace interno o externo, pueden Llamarse explícitamente, se pueden tomar sus direcciones, etc.
Desde la referencia de cpp: http://en.cppreference.com/w/cpp/language/user_literal
Aunque la falla de ANSI C para definir una forma de declaración de variable-argumento que puede manejar limpiamente un tipo long double
precisión extendida cuyo formato difiere del double
ha llevado a que el tipo se desapruebe efectivamente en muchas plataformas (desafortunado, IMHO, ya que fue un buen tipo de uso no solo en sistemas con coprocesadores x87 sino también en sistemas sin FPU ), la única forma sensata de que un sistema con los tipos adecuados de precisión extendida maneje una afirmación como:
long double a = 0.1;
es tener la vida de inicio literal numérica de 0.1 como un long double
igual a 14,757,395,258,967,641,293 / 147,573,952,589,676,412,928; sería absurdo tener esa declaración establecida en 7,205,759,403,792,794 / 72,057,594,037,927,936 (aproximadamente 0.10000000000000000555, el valor de (double)0.1
).
Podría decirse que podría haber algunos casos en los que tener una vida de inicio literal numérica como un long double
antes de convertirse a una conversión descendente podría hacer que produzca un valor diferente de lo que obtendría si comenzara la vida como un double
o float
(por ejemplo, la float
más cercana). Para 9007199791611905.0
es 9007200328482816, que es 536870911 por encima del valor solicitado, pero (float)(double)9007199791611905.0
produce 9007199254740998.08.08.08.08.08.08.08.08.08.08.08.08.08.08.08.08.08.08.08.08.08.08.082582582582582582580060060060000000000000000006006006006006006006006006006006006006006006006006006006006006006006006006006258258256256258006000000000000000000 "" Más ... Más información Está más cerca de lo que uno realmente quiere.
El borrador n3290 de C ++ 11 tiene esto que decir acerca de los parámetros que pueden tomar los literales definidos por el usuario (§13.5.8):
La declaración de un operador literal tendrá una cláusula de declaración de parámetros equivalente a uno de los siguientes:
const char* unsigned long long int long double char wchar_t char16_t char32_t const char*, std::size_t const wchar_t*, std::size_t const char16_t*, std::size_t const char32_t*, std::size_t
Como puede ver, el double
no está en esa lista, solo el long double
es. Así que tienes que usar eso para literales definidos por el usuario que esperan un número de punto flotante como argumento.
Stroustrup tiene una gran sección sobre literales de cadenas donde afirma (de la especificación):
- literal de punto flotante: aceptado por un operador literal que toma un solo argumento long doble o const char *.