模块功能
Lexical_Cast模块提供了一种方便且一致的形式用于支持与任意类型对应的文本和其值之间的通用转换。
版本说明
本文中介绍的Lexical_Cast模块内容是基于Boost 1.56.0的。
模块用法
字符串转数值
#include <boost/lexical_cast.hpp>
#include <iostream>
using namespace std;
int main() {
using boost::bad_lexical_cast;
using boost::lexical_cast;
using boost::conversion::try_lexical_convert;
try {
// 测试使用lexical_cast
short s = lexical_cast<short>("123");
cout << s << endl;
// 测试使用try_lexical_convert
float f;
for (auto str : {"abc", "1.2"}) {
if (try_lexical_convert<float>(str, f)) {
cout << "Succes to convert \"" << str << "\" to " << f << endl;
} else {
cout << "Fail to convert \"" << str << "\" to float" << endl;
}
}
// 测试抛出bad_lexical_cast异常
double d = lexical_cast<double>("123abc");
cout << d << endl;
} catch (const bad_lexical_cast& ex) {
cout << ex.what() << endl;
}
}
上面代码的运行结果如下:
123
Fail to convert "abc" to float
Succes to convert "1.2" to 1.2
bad lexical cast: source type value could not be interpreted as target
数值转字符串
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
using namespace std;
int main() {
using boost::bad_lexical_cast;
using boost::lexical_cast;
using boost::conversion::try_lexical_convert;
//测试使用lexical_cast
const auto s1 = lexical_cast<string>(1.532e5);
cout << s1 << endl;
string s2;
int val = 123;
//测试使用try_lexical_convert
if (try_lexical_convert<string>(val, s2)) {
cout << "Success to convert " << val << " to \"" << s2 << "\"" << endl;
} else {
cout << "Fail to convert " << val << " to string" << endl;
}
}
上面程序的运行结果如下:
153200
自定义类转字符串
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
using namespace std;
class Point {
public:
Point(float x, float y) : x_(x), y_(y) {}
friend ostream &operator<<(ostream &output, const Point &p) {
output << "(" << p.x_ << ", " << p.y_ << ")";
return output;
}
private:
const float x_;
const float y_;
};
int main() {
using boost::bad_lexical_cast;
using boost::lexical_cast;
const auto s = lexical_cast<string>(Point(1.1f, 2.2f));
cout << s << endl;
}
上面程序的运行结果如下:
(1.1, 2.2)
字符串转自定义类
class Point {
public:
friend istream &operator>>(istream &input, Point &p) {
input >> p.x_;
return input;
}
friend ostream &operator<<(ostream &output, const Point &p) {
output << "Point(" << p.x_ << ")";
return output;
}
Point() { x_ =0; }
Point(const Point &pt) {
x_ = pt.x_;
}
private:
float x_;
};
int main() {
using boost::bad_lexical_cast;
using boost::lexical_cast;
const auto p = lexical_cast<Point>(string("3.3"));
cout << p << endl;
}
上面程序的运行结果如下:
Point(3.3)
为什么不使用标准库里的转换
标准C和c++库提供了许多执行此类转换的工具。但是,它们在易用性、可扩展性和安全性方面有所不同。
例如,由atoi代表的标准C函数家族有许多限制:
- 只支持单向转换:从文本到内部数据类型。使用C库以另一种方式进行转换,要么会带来sprintf函数的不便和安全问题,要么会丧失与itoa等非标准函数相关的可移植性;
- 支持的类型范围仅是内置数值类型的子集,即int、long和double;
- 类型的范围不能以统一的方式扩展。例如,将字符串转换成复数(Complex)或有理数(Rational)。
以strtol为代表的标准C函数具有相同的基本限制,但对转换过程提供了更好的控制。然而,对于一般情况,这种控制通常不是不需要就是不使用。
scanf函数家族提供了更强大的控制,但也缺乏安全性和易用性。
标准c++库的stringstream对I/O与文本任意类型之间的格式和转换提供了大量的控制。然而,对于简单的转换,直接使用stringstream可能是笨拙的(引入额外的局部变量并失去了插入表达式的便捷性)或隐晦的(在表达式中创建stringstream对象作为临时对象)。
标准c++库的facet为控制文本表示提供了全面的概念和工具,但是的概它们的复杂性和高入门级别要求对简单的转换进行大量编码,并且除了少数程序员外,所有人都不能参与。