注:转载请保证文章完整性
一、介绍
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
是强大的,但不是万能的,但在很多情况下他有着独特的优点,安全方便快捷!!!