Boost 组件 lexical_cast

字符串→数值

  如何将字符串"123"转换为int类型整数123?答案是,用标准C的库函数atoi;
如果要转换为long类型呢?标准C的库函数atol;
如何将"123.12"转换为double类型呢?标准C的库函数atod;
如果要转换为long double类型呢?标准C的库函数atold;
……
后来有朋友开始使用标准库中的string类,问这个如何转换为数值?有朋友答曰,请先转换为
const char*。我很佩服作答者有数学家的思维:把陌生的问题转化成熟悉的问题。(曾经有一则
笑话,好事者问数学家:知道如何烧水吗?答:知道。把水壶加满水,点火烧。又问:如果水
壶里已经有水了呢?答:先倒掉,就转化为我熟悉的问题了……)
不,不,这样是C的做法,不是C++。那么,C++该怎么做呢?使用Boost Conversion Library
所提供的函数lexical_cast(需要引入头文件boost/lexical_cast.hpp)无疑是最简单方便的。如:

#include <boost/lexical_cast.hpp>
#include <iostream>
int main()
{
using boost::lexical_cast;
int a = lexical_cast<int>("123");
double b = lexical_cast<double>("123.12");
std::cout<<a<<std::endl
std::cout<<b<<std::endl;
return 0;
}

一个函数就简洁地解决了所有的问题。

数值→字符串

那么从数值类型到字符串类型呢?
用itoa?不对吧,标准C/C++里根本没有这个函数。即使在Windows平台下某些编译器提供了该
函数3,没有任何移植性不说,还只能解决int类型(也许其他函数还可以解决long、unsigned long
等类型),浮点类型又怎么办?当然,办法还是有,那就是:sprintf。
char s[100];
sprintf(s, "%f", 123.123456);
不知道诸位对C里的scanf/printf系列印象如何,总之阿炯我肯定记不住那些稀奇古怪的参数,而
且如果写错了参数,就会得到莫名其妙的输出结果,调试起来可就要命了(我更讨厌的是字符
数组,空间开100呢,又怕太小装不下;开100000呢,总觉得太浪费,心里憋气,好在C++标

准为我们提供了string这样的字符串类)。这时候,lexical_cast就出来帮忙啦。

#include <boost/lexical_cast.hpp>
#include <string>
#include <iostream>
int main()
{
using std::string;
const double d = 123.12;
string s = boost::lexical_cast<string>(d);
std::cout<<s<<std::endl;
return 0;
}

跟前面一样简单。

 

异常

如果转换失败,则会有异常bad_lexical_cast抛出。该异常类是标准异常类bad_cast的子类。

#include <boost/lexical_cast.hpp>
#include <iostream>
int main()
{
using std::cout;
using std::endl;
int i;
try{
i = boost::lexical_cast<int>("abcd");
}
catch(boost::bad_lexical_cast& e)
{
cout<<e.what()<<endl;
return 1;
}
cout<<i<<endl;
return 0;
}

显然“abcd”并不能转换为一个int类型的数值,于是抛出异常,捕捉后输出“bad lexical cast:
source type value could not be interpreted as target”这样的信息。

 

注意事项
lexical_cast依赖于字符流std::stringstream(会自动引入头文件4),其原理相当简单:把源类型
读入到字符流中,再写到目标类型中,就大功告成。例如
int d =boost::lexical_cast<int>("123");
就相当于
int d;
std::stringstream s;
s<<"123";
s>>d;
既然是使用了字符流,当然就有些随之而来的问题,需要特别指出5。
由于Visual C++ 6的本地化(locale)部分实现有问题,因此如果使用了非默认的locale,可
能会莫名其妙地抛出异常。当然,一般情况下我们并不需要去改变默认的locale,所以问题
不是很大。
输入数据必须“完整”地转换,否则抛出bad_lexical_cast异常。例如
int i =boost::lexical_cast<int>("123.123"); // this will throw
便会抛出异常。因为“123.123”只能“部分”地转换为123,不能“完整”地转换为123.123。
浮点数的精度问题。
std::string s =boost::lexical_cast<std::string>(123.1234567);
以上语句预想的结果是得到“123.1234567”,但是实际上我们只会得到“123.123”,因为默认
情况下std::stringstream的精度是6(这是C语言程序库中的“前辈”printf留下的传统)。这可以
说是boost::lexical_cast 的一个bug 。怎么办呢? 权宜之计, 可以这么做: 打开头文件
<boost/lexical_cast.hpp>,注意对照修改6:
#include <boost/limits.hpp>
//...
template<typename Target, typename Source>
Target lexical_cast(Source arg) {
//...
Target result;
interpreter.precision(std::numeric_limits<Source>::digits10);
if( !(interpreter << arg) ||
!(interpreter >> result) ||
!(interpreter >> std::ws).eof())
//...
}
即可得到正确结果。当然,理论上效率会有一点点损失,不过几乎可以忽略不计。

posted @ 2009-05-23 17:25  狼窝  阅读(742)  评论(0编辑  收藏  举报