strtoint stoi parse not error declared convert atol c++ c++11 boost stl std

parse - ¿Booster:: lexical_cast es redundante con c++ 11 stoi, stof y family?



stoi in c++ (4)

En cuanto a rendimiento, puedes hacer la comparación usando el siguiente código (es una variación de mi publicación here)

#include <iostream> #include <string> #include <sstream> #include <vector> #include <chrono> #include <random> #include <exception> #include <type_traits> #include <boost/lexical_cast.hpp> using namespace std; // 1. A way to easily measure elapsed time ------------------- template<typename TimeT = std::chrono::milliseconds> struct measure { template<typename F> static typename TimeT::rep execution(F const &func) { auto start = std::chrono::system_clock::now(); func(); auto duration = std::chrono::duration_cast< TimeT>( std::chrono::system_clock::now() - start); return duration.count(); } }; // ----------------------------------------------------------- // 2. Define the convertion functions ======================== // A. Using boost::lexical_cast ------------------------------ template<typename Ret> Ret NumberFromString(string const &value) { return boost::lexical_cast<Ret>(value); } // B. Using c++11 stoi() ------------------------------------- int IntFromString(string const &value) { return std::stoi(value); } // C. Using c++11 stof() ------------------------------------- float FloatFromString(string const &value) { return std::stof(value); } // =========================================================== // 3. A wrapper to measure the different executions ---------- template<typename T, typename F> long long MeasureExec(std::vector<string> const &v1, F const &func) { return measure<>::execution([&]() { for (auto const &i : v1) { if (func(i) != NumberFromString<T>(i)) { throw std::runtime_error("FAIL"); } } }); } // ----------------------------------------------------------- // 4. Machinery to generate random numbers into a vector ----- template<typename T> typename std::enable_if<std::is_integral<T>::value>::type FillVec(vector<T> &v) { mt19937 e2(1); uniform_int_distribution<> dist(3, 1440); generate(v.begin(), v.end(), [&]() { return dist(e2); }); } template<typename T> typename std::enable_if<!std::is_integral<T>::value>::type FillVec(vector<T> &v) { mt19937 e2(1); uniform_real_distribution<> dist(-1440., 1440.); generate(v.begin(), v.end(), [&]() { return dist(e2); }); } template<typename T> void FillVec(vector<T> const &vec, vector<string> *result) { result->resize(vec.size()); for (size_t i = 0; i < vec.size(); i++) result->at(i) = boost::lexical_cast<string>(vec[i]); } // ----------------------------------------------------------- int main() { std::vector<int> vi(991908); FillVec(vi); std::vector<float> vf(991908); FillVec(vf); std::vector<string> vsi, vsf; FillVec(vi, &vsi); FillVec(vf, &vsf); cout << "C++ 11 stof function .. " << MeasureExec<float>(vsf, FloatFromString) << endl; cout << "Lexical cast method ... " << MeasureExec<float>(vsf, NumberFromString<float>) << endl; cout << endl << endl; cout << "C++ 11 stoi function .. " << MeasureExec<int>(vsi, IntFromString) << endl; cout << "Lexical cast method ... " << MeasureExec<int>(vsi, NumberFromString<int>) << endl; return 0; }

Cuando se executed con

g ++ -std = c ++ 11 -Desnudo -march = native -Wall -pedantic main.cpp && ./a.out

Los resultados son

Función C ++ 11 stof .. 540

Método de lanzamiento léxico ... 559

C ++ 11 función stoi .. 117

Método de lanzamiento léxico ... 156

Las funciones especializadas C ++ 11 ciertamente parecen funcionar mejor. Pero son exactamente eso, especializados , y como tales hacen que la construcción de interfaces abstractas sea más difícil que el lexical_cast

¿ boost::lexical_cast redundante ahora que C ++ 11 introduce stoi , stof y family, o hay alguna razón para seguir utilizándolo? (además de no tener un compilador C ++ 11) ¿Ofrecen exactamente la misma funcionalidad?


boost :: lexical_cast es más que convertir a un conjunto distinto de tipos:

struct A {}; std::ostream& operator << (std::ostream& stream, const A&) { return stream; } struct B {}; std::istream& operator >> (std::istream& stream, B&) { return stream; } int main(){ A a; B b = boost::lexical_cast<B>(a); }

Su punto fuerte y su debilidad es la aceptación de cualquier par de tipos para la conversión a través de un estándar std :: stringstream (donde se aplica o no un algoritmo optimizado).


boost::lexical_cast

  • maneja más tipos de conversión , incluidos pares de iteradores, matrices, cadenas C, etc.
  • ofrece la misma interfaz genérica ( sto* tiene diferentes nombres para diferentes tipos)
  • es sensible a la configuración regional ( sto* / to_string son solo en parte, por ejemplo, lexical_cast puede procesar separadores de miles, mientras que stoul no suele)

boost::lexical_cast le ofrece una interfaz uniforme entre los tipos, que a menudo es muy importante en el código genérico.

En general, una interfaz coherente entre los tipos para la misma funcionalidad permite un mejor código genérico. Por ejemplo, follow se puede usar como analizador genérico desde tokens de cadena a std :: tuple:

template<typename T> void fill(T& item, const std::string& token){ item = boost::lexical_cast<T>(token) } template<int N, typename ...Ts> void parse(std::integral_constant<int, N>, std::tuple<Ts...>& info, std::vector<std::string>& tokens) { fill(std::get<N>(info), tokens[N]); parse(std::integral_constant<int, N - 1>, info, tokens); } template<typename ...Ts> void parse(std::integral_constant<int, 0>, std::tuple<Ts...>& info, std::vector<std::string>& tokens) { fill(std::get<0>(info), tokens[0]); }

En lugar de tupla, a menudo utilizo boost fusion struct para deserializar algunas cadenas tokenizadas directamente en una estructura de una manera genérica.