Es boost:: lexical cast redundante con c++11 stoi, stof y family?


Es boost::lexical_cast redundantes ahora que C++11 introduce stoi, stof y de la familia, o hay alguna razón para utilizarlo? (aparte de no tener un compilador de C++11) ¿Proporcionan exactamente la misma funcionalidad?

Author: herohuyongtao, 2014-05-10

4 answers

boost::lexical_cast

  • maneja más tipos de conversión, incluyendo pares 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 miles de separadores, mientras que stoul generalmente no)
 20
Author: Cubbi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-22 02:04:18

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

En general, la interfaz consistente entre tipos para la misma funcionalidad permite un mejor código genérico. Por ejemplo, lo siguiente se puede usar como analizador genérico de 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 uso boost fusion struct para deserializar algunas cadenas tokenizadas directamente en una estructura de una manera genérica.

 18
Author: apoorvkul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-19 13:14:44

En cuanto al rendimiento, puedes hacer la comparación usando el siguiente código (es una variación de mi post aquí)

#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 ejecutado con

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

Los resultados son

C++ 11 función stof .. 540

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

C++ 11 función stoi .. 117

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

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

 5
Author: Nikos Athanasiou,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:43

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 fuerza y debilidad es la aceptación de cualquier par de tipos para la conversión a través de un std::stringstream intermedio (donde se aplica o no un algoritmo optimizado).

 3
Author: Dieter Lücking,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-10 15:10:48