En la biblioteca estándar de C ++ hay funciones para convertir de cadena a tipos numéricos:
stoi
stol
stoll
stoul
stoull
stof
stod
stold
pero me resulta tedioso usarlos en el código de plantilla. ¿Por qué no hay funciones de plantilla?
template<typename T>
T sto(...)
convertir cadenas a tipos numéricos?
No veo ninguna razón técnica para no tenerlos, pero tal vez me estoy perdiendo algo. Se pueden especializar para llamar a las funciones nombradas subyacentes y usar enable_if
/ concepts
para deshabilitar tipos no numéricos.
¿Existen alternativas amigables con las plantillas en la biblioteca estándar para convertir cadenas a tipos numéricos y viceversa de una manera eficiente?
c++
string-conversion
Mircea Ispas
fuente
fuente
Respuestas:
C ++ 17 tiene una función genérica de cadena a número, pero se nombra de manera diferente. Fueron con
std::from_chars
, que está sobrecargado para todos los tipos numéricos.Como puede ver, la primera sobrecarga toma cualquier tipo entero como parámetro de salida y le asignará el valor si es posible.
Se puede usar así:
Como puede ver, puede funcionar en un contexto genérico.
fuente
No es una plantilla, y no funciona con configuraciones regionales, pero si eso no es un show stopper, entonces C ++ 17 ya tiene lo que desea:
std::from_chars
Hay sobrecargas para todos los tipos enteros y de punto flotante y la interfaz es la misma, excepto los últimos parámetros que son diferentes para los tipos enteros y de punto flotante respectivamente (pero si el valor predeterminado es correcto, entonces no necesita Cambia cualquier cosa). Debido a que esta no es una función local, también es bastante rápida. Batirá cualquiera de las otras funciones de conversión de cadena a valor y, en general, es por orden de magnitud.
Hay un muy buen video de CPPCON sobre
<charconv>
(el encabezadofrom_chars
vive) de Stephan T. Lavavej que puedes ver sobre su uso y rendimiento aquí: https://www.youtube.com/watch?v=4P_kbF0EbZMfuente
stoi
y sus amigos (las conversiones mencionadas en la pregunta) tampoco funcionan con las configuraciones regionales, por lo que no es un showtopper.No ganarías mucho porque en una expresión como
No hay forma (fácil) de deducir el tipo deseado para el parámetro de plantilla. Tendrias que escribir
que en cierta medida derrota el propósito de proporcionar una función genérica. Por otro lado, un
sería de gran utilidad como te diste cuenta. En C ++ 17 existe
std::from_chars
, que hace más o menos exactamente eso (no es una plantilla sino un conjunto de sobrecargas y toma punteros a caracteres en lugar de una cadena, pero eso son solo detalles menores).PD No hay una manera fácil de deducir el tipo deseado en la expresión anterior, pero hay una manera. No creo que el núcleo de su pregunta sea exactamente la firma que solicitó, y no creo que la siguiente sea una buena manera de implementarla, pero sabía que hay una manera de hacer la
int x = sto("1");
compilación anterior y tenía curiosidad por verla. en acción.Esto funciona según lo previsto, pero tiene graves inconvenientes, quizás lo más importante es que permite escribir
auto x = sto(s);
, es decir, es fácil de usar incorrectamente.fuente
auto x = sto(s)
? Esta implementación particular se rompe porqueconverter::x
es una referencia que está fuera de alcance, pero eso se puede solucionar. Simplemente elimine la referencia y confíe enstd::string
la semántica de movimiento.converter
, además, no estoy seguro de si usar un operador de conversión de plantillas fue la mejor opción, cosas que podrían solucionarse. Tal vez no sea tan malo como pensé inicialmenteLa solución compatible con todos (incluso los compiladores de C ++ más antiguos, como los de C ++ - 98) es utilizar boost :: lexical_cast, que es una plantilla para convertir entre tipos numéricos y de cadena de ambas maneras.
Ejemplo:
Ver: https://www.boost.org/doc/libs/1_42_0/libs/conversion/lexical_cast.htm
fuente
En versiones anteriores de C ++, stringstream es tu amigo. Si lo entiendo correctamente, entonces lo siguiente podría ser interesante para usted. Es C ++ 11.
https://wandbox.org/permlink/nUNiUwWWTr7a0NXM
Este método funciona en C ++ 11 y es bastante general. En mi experiencia, este método es robusto, pero no el más eficaz.
fuente