注:转载请保证文章完整性
一、介绍
lexical_cast是boost中一个非常有用,常用,好用的库,我现在的小数据转换用的都是lexical_cast。 lexical_cast最大的特点是安全,包括长度安全,类型安全。 下面我来介绍下lexical_cast的基本使用方法。
Target lexical_cast(Source arg)
例如:
#include <boost/lexical_cast.hpp>           
using namespace std;                        
using namespace 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>           
using namespace std;                        
using namespace 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;                       
using namespace 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 
                             
    #include <strstream>
#else
    #include <sstream>
#endif
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)
        {
        }
        
        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是强大的,但不是万能的,但在很多情况下他有着独特的优点,安全方便快捷!!!