【转载】boost的lexical_cast --数据类型转换

本文详细介绍Boost库中的lexical_cast函数,包括其基本使用方法、异常处理机制,并通过实例演示如何进行类型安全的数据转换。
注: 转载请保证文章完整性

一、介绍


lexical_cast是boost中一个非常有用,常用,好用的库,我现在的小数据转换用的都是lexical_cast。
lexical_cast最大的特点是安全,包括长度安全,类型安全。
下面我来介绍下lexical_cast的基本使用方法。

Target lexical_cast(Source arg)

例如 
#include <boost/lexical_cast.hpp>           //lexical_cast的头文件
using namespace std;                        //stl的域
using namespace boost;                      //boost的域
int main()
    {
    const double PI=3.1415926535;
    string str;
    str=lexical_cast<string>(PI);
    cout<<str; 
    return 0;
    }

非常容易吧,简单也是他的优势之一。


二、异常


lexical_cast在执行失败时会抛出异常bad_lexical_cast
上面的例子改为
#include <boost/lexical_cast.hpp>           //lexical_cast的头文件
using namespace std;                        //stl的域
using namespace boost;                      //boost的域
int main()
    {
    try
        {
        string str="3.1415926535";
        double PI=lexical_cast<double>(str);
        cout<<PI; 
        return 0;
        }
    catch(bad_lexical_cast& E)
        {
        cout<<E.what()<<endl;
        }
    }

当str为ABCD时,
无法转成PI抛出异常
输出
bad lexical cast: source type value could not be interpreted as target



三、一个小例子


为了加深大加理解
下面使用lexical_cast实现一个简单的文本输入是否为指定类型的小程序

#include <boost/lexical_cast.hpp>
#include <iostream>
using namespace std;                        //stl的域
using namespace boost;                      //boost的域
template<typename _T,typename _R>
bool isElement(_R r)
    {
    try
        {
        lexical_cast<_T>(r);                
        return true;                        //转换成功
        }
    catch(...)
        {
        return false;
        }
    }
int main()
    {
    try
        {

        if(isElement<double>("3.14d159"))
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
        }
    catch(bad_lexical_cast& E)
        {
        cout<<E.what()<<endl;
        }
    return 0;    
    }

测试:isElement<double>("3.14d159") 输出:NO
测试:isElement<string>("3.14d159") 输出:YES
测试:isElement<long>("314159")     输出:YES
测试:isElement<long>("31.4159")    输出:NO
测试:isElement<char>("314159")     输出:NO



四、源码分析


#ifdef BOOST_NO_STRINGSTREAM        //我们知道stringstream和strstream分别是string和char*结构,lexical_cast考虑很全面的。
#include <strstream>
#else
#include <sstream>
#endif

// bad_lexical_cast是bad_cast的继承,所以很标准,支持和扩充性都很好。
    class bad_lexical_cast : public std::bad_cast 
    {
    public:
        bad_lexical_cast() :
        source(&typeid(void)), target(&typeid(void))
        {
        }
        bad_lexical_cast(
            const std::type_info &s,
            const std::type_info &t) :
            source(&s), target(&t)
        {
        }
//提供了两个返回type_info的函数,为我们跟踪调试类形转换起到很好
        const std::type_info &source_type() const 的做用。
  
 作者: 221.239.187.*  2006-1-2 15:09   回复此发言  
 
2boost的lexical_cast
 
        {
            return *source;
        }
        const std::type_info &target_type() const
        {
            return *target;
        }
        virtual const char *what() const throw()
        {
            return "bad lexical cast: "
                   "source type value could not be interpreted as target";
        }
        virtual ~bad_lexical_cast() throw()
        {
        }
    private:
        const std::type_info *source;
        const std::type_info *target;
    };

type_info的具体用法是:
E.source_type().name()就可能到类型名。

核心转换部分,用的是留的概念,从流内数据的剩余情况与流转换成功与否情况来判断操作是否成功。在不加域时这里就像一个黑盒子。

            bool operator<<(const Source &input)
            {
                return !(stream << input).fail();
            }
            template<typename InputStreamable>
            bool operator>>(InputStreamable &output)
            {
                return !is_pointer<InputStreamable>::value &&
                       stream >> output &&
                       (stream >> std::ws).eof();
            }
            bool operator>>(std::string &output)
            {
                #if defined(BOOST_NO_STRINGSTREAM)
                stream << '\0';
                #endif
                output = stream.str();
                return true;
            }



仅提供该入口,具体实现被封在detail域里面。
    template<typename Target, typename Source>
    Target lexical_cast(Source arg)
    {
        detail::lexical_stream<Target, Source> interpreter;
        Target result;

        if(!(interpreter << arg && interpreter >> result))
            throw_exception(bad_lexical_cast(typeid(Target), typeid(Source))); //抛出异常错误,
        return result;
    }


最后
我们可以发现
bad_lexical_cast(typeid(Target), typeid(Source) 与上面
bad_lexical_cast(const std::type_info &s,const std::type_info &t) 
        :source(&s), target(&t)

之间的区别,在我看来是写倒了,不过不影响,也算是个不算bug的bug



五、总结

lexical_cast是强大的,但不是万能的,但在很多情况下他有着独特的优点,安全方便快捷!!!
### boost::lexical_cast 处理 double 类型时的精度范围 `boost::lexical_cast` 是一个用于在不同数据类型之间进行转换的工具,它依赖于标准库中的流操作(如 `std::stringstream`)来实现类型转换。当涉及到 `double` 类型时,`boost::lexical_cast` 的精度主要取决于以下几个因素: 1. **底层流机制的精度限制**: `boost::lexical_cast` 内部使用 `std::stringstream` 来执行类型转换,而 `std::stringstream` 的精度由其默认设置或显式设置的格式化标志决定。默认情况下,浮点数的输出精度由 `std::numeric_limits<double>::digits10` 控制,通常为 15-17 位十进制数字[^1]。 2. **IEEE 754 标准的限制**: C++ 中的 `double` 类型遵循 IEEE 754 双精度浮点数标准,能够表示大约 15-17 位有效数字。这意味着,即使 `boost::lexical_cast` 在转换过程中没有引入额外误差,`double` 类型本身的精度限制也会导致结果最多保留 15-17 位有效数字[^3]。 3. **输入字符串的格式**: 如果输入是一个字符串形式的数字,`boost::lexical_cast` 的精度还会受到该字符串中数字的有效位数影响。例如,字符串 `"12345678901234567890"` 超过了 `double` 类型的精度范围,因此在转换为 `double` 后,可能会丢失部分低阶位信息[^2]。 4. **异常处理与精度控制**: 如果需要更高的精度控制,可以考虑使用 `try_lexical_convert` 函数,它提供了一种不抛出异常的方式进行类型转换,并允许用户检查转换是否成功。这在处理可能超出 `double` 精度范围的数值时特别有用[^3]。 以下是一个示例代码,展示如何使用 `boost::lexical_cast` 转换 `double` 类型并观察其精度: ```cpp #include <boost/lexical_cast.hpp> #include <iostream> #include <limits> int main() { try { // 测试高精度字符串到 double 的转换 std::string highPrecisionStr = "12345678901234567890"; double result = boost::lexical_cast<double>(highPrecisionStr); std::cout << "Converted value: " << result << std::endl; // 检查 double 的精度限制 std::cout << "Maximum digits10 for double: " << std::numeric_limits<double>::digits10 << std::endl; } catch (const boost::bad_lexical_cast& e) { std::cerr << "Conversion failed: " << e.what() << std::endl; } return 0; } ``` ### 注意事项 - 当输入字符串包含超过 `double` 精度范围的数字时,`boost::lexical_cast` 不会抛出异常,而是会截断超出范围的部分。 - 如果需要更高的精度(例如支持任意精度的数学运算),可以考虑使用专门的库,如 `Boost.Multiprecision` 或其他大数库[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值