10.3.5 boost::lexical_cast
boost::lexical_cast用于实现字符串和某些数据类型的转换。常见的如整值与字符串之前的转换:
#include <boost/lexical_cast.hpp>
...
//把字符串转换为......
int i = boost::lexical_cast <int> ("1024");
long l = boost::lexical_cast <long> ("20130");
double d = boost::lexical_cast <double> ("0.123");
//把其他类型转换为字符串
string si = boost::lexical_cast <string> (i);
string sl = boost::lexical_cast <string> (l);
string sd = boost::lexical_cast <string> (d);
可见其用法是:目标数据 = lexical_cast <目标类型> (源数据),形式和用法都和C++内置的static_cast <> ()等转换操作非常一致。
利用“std::stringstream”,可以模拟lexical_cas的功能,从而加深对它的理解:
#include <sstream>
...
namespace my
{
template<typename TObj, typename TSrc>
TObj lexical_cast(TSrc const& src)
{
std::stringstream ss;
ss << src; //吃进源
TObj obj;
ss >> obj; //吐出目标
return obj;
}
}
把前面测试boost::lexical_cast的代码,相关内容改为“my::lexical_cast”,看到的测试效果一致,虽然还是山寨班子,但所用的技术却和原厂的lexical_cast基本一致。
都是利用了C++的“输入输出流”,可以“吃入”多种类型的数据,再以另外一种类型“吐”出来的基础(有点像魔术盒子),来实现数据在不同类型之间的转换。
C++的“流(stream)”对象也不是什么类型的数据都吃得进去或吐得出来的。用户自定义的数据,它就处理不了,比如有个坐标点:
struct MyPoint
{
int x, y;
};
原装的lexical_cast暂时也不能把MyPoint的对象转换成字符串:
MyPoint pt;
string smp = boost::lexical_cast <MyPoint> (pt);
怎么办?解决方法是,为MyPoint分别提供输出与输入流的重载即可:
struct MyPoint
{
int x, y;
};
//输出重载
ostream& operator << (ostream& os, MyPoint const& pt)
{
os << pt.x << ' ' << pt.y; //两个数用一个空格分隔
return os;
}
//输入重载
istream& operator >> (istream& is, MyPoint& pt)
{
is >> pt.x >> pt.y;
return is;
}
然后先测试一下将MyPoint转成字符串:
void test_custom_lexical_cast()
{
MyPoint pt;
pt.x = 90;
pt.y = -80;
string s = boost::lexical_cast <string> (pt);
cout << "pt1: " << s << endl;
}
演示:
成功了!屏幕输出s的值是:“90 -80”。
既然输入重载也已经写好了,那么上面的s再转回MyPoint应该也是妥妥的了。
void test_custom_lexical_cast()
{
MyPoint pt;
...
string s = boost::lexical_cast <string> (pt);
...
MyPoint pt2;
pt2 = boost::lexical_cast <MyPoint> (s);
}
编译,运行,程序居然异常退出了,报告是bad_lexical_cast......
突然想起山寨版本,将前面最后一代码改成“pt2 = my::lexical_cast <MyPoint> (s);”
居然成功了,顺利的将s转换成pt2。
原因很简单,istream默认启用了 std::ios::skipws 参数,当读入两个整数时,中间的空格被自动跳过。我们的代码“is >> pt.x >> pt.y”利用了这个特性,能够正确地从流中读出 x 和 y 的值。
boost::lexical_cast所使用的流,为了严格起见,主动关闭了 std::ios::skipws参数。所以我们的代码做如下修改:
/* 根据boost::lexical_cast内部流的要求,
重写MyPoint输入流的操作 */
istream& operator >> (istream& is, MyPoint& pt)
{
// is >> pt.x >> pt.y;
is >> pt.x;
is.get(); //跳过空格
is >> pt.y;
return is;
}
再次运行,依然成功