Khan's Notebook GCC/GNU/Linux Delphi/Window Java/Anywhere

路漫漫,长修远,我们不能没有钱
随笔 - 172, 文章 - 0, 评论 - 257, 引用 - 0
数据加载中……

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 
        {
            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是强大的,但不是万能的,但在很多情况下他有着独特的优点,安全方便快捷!!!

posted on 2017-10-14 16:26 Khan 阅读(746) 评论(0)  编辑 收藏 引用 所属分类: GCC/G++跨平台开发


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理