C++ boost::词法强制转换是否与c++;11斯托伊,斯托夫和家庭?

C++ boost::词法强制转换是否与c++;11斯托伊,斯托夫和家庭?,c++,c++11,boost,stl,std,C++,C++11,Boost,Stl,Std,既然C++11引入了和系列,那么boost::lexical_cast是多余的,还是有理由继续使用它?(除了没有C++11编译器之外)它们是否提供完全相同的功能?boost::lexical_cast为您提供了跨类型的统一接口,这在泛型代码中通常非常重要 一般来说,相同功能的跨类型一致接口可以更好地支持通用代码。例如,以下内容可用作从字符串标记到std::tuple的通用解析器: template<typename T> void fill(T& item, const st

既然C++11引入了和系列,那么boost::lexical_cast是多余的,还是有理由继续使用它?(除了没有C++11编译器之外)它们是否提供完全相同的功能?

boost::lexical_cast为您提供了跨类型的统一接口,这在泛型代码中通常非常重要

一般来说,相同功能的跨类型一致接口可以更好地支持通用代码。例如,以下内容可用作从字符串标记到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]);
}
模板
空白填充(T&item,常量标准::字符串和标记){
item=boost::词法转换(令牌)
} 
模板
void解析(std::integral_常量、std::tuple&info、std::vector&tokens){
填充(std::get(info),令牌[N]);
解析(std::整型常量、信息、标记);
}
模板
void解析(std::integral_常量、std::tuple&info、std::vector&tokens){
填充(std::get(info),令牌[0]);
}

我经常使用tuple来代替tuple,以一种通用的方式将一些标记化字符串直接反序列化到结构中。

boost::lexical_cast

  • 句柄,包括迭代器对、数组、C字符串等
  • 提供相同的通用接口(
    sto*
    对不同类型有不同的名称)
  • 对区域设置敏感(
    sto*
    /
    to_string
    仅部分敏感,例如
    词法转换
    可以处理数千个分隔符,而
    stoul
    通常不能)

boost::词法转换不仅仅是转换为一组不同的类型:

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);
}
struct A{};
std::ostream&operator>(std::istream&stream,B&){
回流;
}
int main(){
A A;
B=boost::词法转换(a);
}

它的优点和缺点是通过中间的std::stringstream(无论是否应用了优化算法)接受任何类型的转换。

从性能角度看,您可以使用以下代码进行比较(这是我文章的一个变体

#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
//1.一种易于测量经过时间的方法-------------------
模板
结构度量
{
模板
静态typename TimeT::rep执行(F const&func)
{
自动启动=标准::时钟::系统时钟::现在();
func();
自动持续时间=标准时间:持续时间(
std::chrono::system_clock::now()-start);
返回duration.count();
}
};
// -----------------------------------------------------------
//2.定义转换函数========================
//A.使用boost::词法转换------------------------------
模板
Ret NumberFromString(字符串常量和值){
返回boost::词法转换(值);
}
//B.使用c++11 stoi()-------------------------------------
int IntFromString(字符串常量和值){
返回标准::stoi(值);
}
//C.使用C++11 stof()进行编程-------------------------------------
float FloatFromString(字符串常量和值){
返回std::stof(值);
}
// ===========================================================
//3.测量不同执行情况的包装器----------
模板长
MeasureExec(标准::向量常数和v1,F常数和函数)
{
返回度量::执行([&](){
用于(自动常数和i:v1){
if(func(i)!=NumberFromString(i)){
抛出std::运行时_错误(“失败”);
}
}
});
}
// -----------------------------------------------------------
//4.将随机数生成向量的机器-----
模板
typename std::enable_if::type
FillVec(矢量和v)
{
mt19937 e2(1);
均匀分布区(31440);
生成(v.begin(),v.end(),[&](){returndist(e2);});
}
模板
typename std::enable_if::value>::type
FillVec(矢量和v)
{
mt19937 e2(1);
均匀实分布区(-1440,1440.);
生成(v.begin(),v.end(),[&](){returndist(e2);});
}
模板
无效填充向量(向量常量和向量,向量*结果)
{
结果->调整大小(向量大小());
对于(size_t i=0;iat(i)=boost::词法转换(vec[i]);
}
// -----------------------------------------------------------
int main()
{
标准:向量vi(991908);
FillVec(vi);
标准::矢量vf(991908);
FillVec(vf);
std::向量vsi,vsf;
FillVec(vi和vsi);
FillVec(vf和vsf);

还可以,但是可以详细说明一下吗?一些示例?VS 2012的
stoi
to_string
的实现,如果我没记错的话,每次初始化
stringstream
。效率非常低。@C.R.关于性能问题,我的回答是谢谢,这似乎是最好的总结。还有apoorvkul很好地解释了通用接口的原因。
lexical_cast
在许多情况下也比标准库快:
#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;
}