boost/lexical_cast.hpp
Motivation
Examples
Synopsis
lexical_cast
bad_lexical_cast
Changes
--------------------------------------------------------------------------------
动机:
有些时候,例如一个被表示成string格式的int,或者当一个string被解释成int时,一个数值必须被转换为文本格式。在程序内部数据类型与程序外部的数据表示之间的转换中,不乏这样的例子。
C和C++的标准库中提供许多执行这种转换的方法。但是,它们在使用的方便性、可扩展性以及安全性上各不相同。
比如,在使用与C标准函数atoi系列时,存在大量的局限性:
-只允许从文本向整数类型一个方向上的转换。利用C函数库进行反方向的转换时,要么选择sprintf函数的不方便性和不安全性,要么选择非标准函数如itoa的不可移植性。
-支持转换的类型只是内置数值类型的一部分,也就是int、long和double。
-不能以统一的方式进行扩展,例如,将文本表示转换为complex或rational。
以strtol为代表的标准C库存在同样的基本限制,但能够很好控制转换过程。然而,在通常情况下,这些控制既不需要也不会被使用。scanf系列函数提供更为强大的控制,但也缺乏安全性以及使用的方便性。
标准C++库提供stringstream来处理这种内置核心类型的格式化。它提供了从任意类型到文本类型的格式化以及从文本类型到任意类型的转换过程中的大量控制。然而,直接应用stringstream进行简单的转换,要么显得很笨拙(由于声明额外的本地变量以及中缀表示式降低方便性),要么显得很晦涩难懂(当stringstream作为一个在表达式中生成的临时对象时)。众多方面构成了一个综合的概念,并提供控制文本表示的机制,但是它们已知的复杂性和高门槛导致一个简单的转换都需要极端程度的深入,从而将众多程序员拒之门外。
lexical_cast函数模板提供一种方便和统一的方式来处理从或到任意表示为文本形式的类型的普通转换。这种方法的简单性存在于进行转换时表达式上形式上的方便性。为了更进一步转换,例如在那些精度或格式相对于lexical_cast的默认行为需要更加严格控制的地方,stringstream的转换方式是可取的。在数值之间进行转换时,numeric_cast可能比lexical_cast更加可取。
涉及字符串格式化的选项和事件的完善的论述 ,包括stringstream,lexical_cast及其他方法之间的比较,可以参考Herb Sutter的文章 The String Formatters of Manor Farm.
--------------------------------------------------------------------------------
例子:
接下来的例子将命令行参数当作一个数值序列。
int main(int argc, char * argv[])
{
using boost::lexical_cast;
using boost::bad_lexical_cast;
std::vector<short> args;
while(*++argv)
{
try
{
args.push_back(lexical_cast<short>(*argv));
}
catch(bad_lexical_cast &)
{
args.push_back(0);
}
}
...
}
下例在一个文本表达式中使用数值:
void log_message(const std::string &);
void log_errno(int yoko)
{
log_message("Error " + boost::lexical_cast<std::string>(yoko) + ": " + strerror(yoko));
}
--------------------------------------------------------------------------------
大纲
库特征定义于"boost/lexical_cast.hpp":
namespace boost
{
class bad_lexical_cast;
template<typename Target, typename Source>
Target lexical_cast(Source arg);
}
lexical_cast
template<typename Target, typename Source>
Target lexical_cast(Source arg);
返回
在Target是std::string或std::wstring的地方,流提取整条字符串,包括空格,而不是依赖操作符>>默认操作。
如果转换不成功,就会抛出一个bad_lexical_cast异常。
对参数和返回类型的要求有:
将流参数的结果返回为一个标准库中基于字符串的流,并将结果保存在一个Target对象。
Source是OutputStreamable,是指操作符<<被定义,它从左边获取std::ostream或std::wostream对象,从右边获取参数类型的对象。
Target是InputStreamable,是指操作符>>被定义,它从左边获取std::ostream或std::wostream对象,从右边获取参数类型的对象。
Source和Target都有复制构造函数。
Target 可默认构造的,是指它能够默认初始化对应类型的一个对象。
当Source或Target需求一个宽字符流,底层的stream将使用wchar_t,除此之外,底层的stream的字符类型都采取为char。Sourcet类型中要求使用宽字符流的有wchar_t, wchar_t*和std::wstring。Target类型中要求使用宽字符流的有wchar_t和std::wstring。
在需要对转换做更深控制的地方,std::stringsream和std::wstringstream提供了一种更合适的方法。在需要不基于流进行转换的地方,lexical_cast不是实现此工作的正确手段,同时也不是针对这种场合的特殊情形。
--------------------------------------------------------------------------------
bad_lexical_cast
class bad_lexical_cast : public std::bad_cast
{
public:
... // same member function interface as std::exception
};
表明lexical_cast运行失败的异常 .
--------------------------------------------------------------------------------
修改
6月 2005
使用传const引用传入参数. 这要求对类模板进行部分特化,所以他不能在MSVC6下运行,此时使用原来的传值。
对MSVC6的支持被抗议,在Boost未来的版本中将会被除去。
Earlier:
上一个版本的lexical_cast使用默认的stream精度读取和写入浮点数值。对于有一个std::numeric_limits对应特化的数值,目前版本选择一种精度来匹配。
上一个版本的lexical_cast不支持到或从基于宽字符的类型的转换。对于在语言和库上支持宽字符的编译器上,lexical_cast目前已支持从wchar_t,wchar_t*和std::wstring已经到wchar_t和std::wstring的转换。
上一个版本的lexical_cast假定传统的流的提取操作符足够应付读取数值操作。然而,由于空格充当了I/O分隔符的角色而不是当作字符串内容的原因,字符串I/O是不对称的。目前版本的修正了处理std::string时的这个错误,std::wstring:lexical_cast<std::string>("Hello, World") 成功执行,而不是以抛出bad_lexical_cast异常。
上一个版本的lexical_cast允许不安全和毫无意义的向指针的转换。当前版本现在处理向指针转换时抛出bad_lexical_cast异常:lexical_cast<char*>("Goodbye, World")现在抛出bad_lexical_cast异常而不是未知行为。