读书人

boost:conversion

发布时间: 2012-10-18 13:46:56 作者: rapoo

boost::conversion


Conversion

C++中的类型转换很容易,但又很难保证安全。如何写出一个安全的dynamic_cast?如何在数字转换时保证不溢出?有没有不依赖iostream的字符串<->类型 的转换?有boost!

?

polymorphic_cast 转型函数??????? <boost/cast.hpp>

用dynamic_cast做向下转换是一种比较危险的操作,如果失败,返回值为0.但很多人并没有检测它的返回值。polymorphic_cast用以替代dynamic_cast的指针转换,如果失败,它会抛出异常。注意,它不用于引用的转换,因为引用不可能为空,dynamic_cast能完成这项工作。

polymorphic_downcast 转型函数??????? <boost/cast.hpp>

dynamic_cast做向下转换时没有static_cast快,不过static_cast只是对指针做运算,即使失败也不会返回0或抛出异常,因此现实中没人用它做向下转换(当然,有一些初学者会)。如果确实很在于static_cast节约那点时间,polymorphic_downcast更适合,它就像一个宏,在debug时它用dynamic_cast,在release时用static_cast替代。听起来不错,但有时候优化过度就会成bug了。

numeric_cast 转型函数??????? <boost/cast.hpp>

numeric_cast保证在数字转换时的安全性。如?short t = numeric_cast<short>(i);
如果 i 大于了std::numeric_limits<short>::max(), 它就抛出一个异常。呵呵,你大概也知道,无符号数不存在溢出,如果你用numeric_cast它照样会抛出异常,所以用不用就看你自己了。附带提一句,std::numeric_limits<T> 也是很常用的,不要忘记了。

lexical_cast 转型函数??????? <boost/lexical_cast.hpp>

把字符串转换为数值,反之亦然。它可以看作是使用std::stringstream的解释器,它同样利用<<和>>。另外如果不匹配,会抛出异常。有了它,彻底抛弃atoi , itoa吧。

?

?

?

lexical_cast?

http://hi.baidu.com/%C2%CC%B2%E8%B0%A1%CF%EB/blog/item/19ff98915dd70e7f54fb9670.html

头文件:?"boost/lexical_cast.hpp"

?

所有应用都会使用字面转换。我们把字符串转为数值,反之亦然。许多用户定义的类型可以转换为字符串或者由字符串转换而来。你常常是在需要这些转换时才编写代码,而更好的方法是提供一个可重用的实现。这就是?lexical_cast的用途所在。你可以把lexical_cast?想象为使用一个?std::stringstream?作为字符串与数值的表示之间的翻译器。这意味着它可以与任何用operator<<进行输出的源以及任何用operator<<进行输入的目标一起工作。这个要求对于所有内建类型与多数用户自定义类型(UDTs)都可以做到。

用法

lexical_cast?在类型之间进行转换,就象其它的类型转换操作一样。当然,使它得以工作的必须是一个转换函数,但从概念上说,你可以把它视为转型操作符。比起调用一堆的转换子程序,或者是编写自己的转换代码,lexical_cast?可以更好地为任何满足它的要求的类型服务。它的要求就是,源类型必须是可流输出的(OutputStreamable),而目标类型必须是可流输入的 (InputStreamable)。另外,两种类型都必须是可复制构造的(CopyConstructible),并且目标类型还要是可缺省构造的 (DefaultConstructible)和可赋值的(Assignable)。可流输出(OutputStreamable)意味着存在一个为该类型定义的operator<<,可流输入(InputStreamable)则要求有一个operator>>. 对于许多类型,包括所有内建类型和标准库中的字符串类型,这个条件都满足。要使用?lexical_cast, 就要包含头文件?"boost/lexical_cast.hpp".

让?lexical_cast?工作

我不想通过跟你示范手工编写转换用的代码来说明?lexical_cast?如何节省了你的时间,因为我可以很肯定你一定写过这样的转换代码,并且很可能不只一次。相反,只用一个例子来示范如何使用?lexical_cast?来进行通用的(字面上的)类型转换。

#include <iostream>
#include <string>
#include "boost/lexical_cast.hpp"

int main() {
// string to int
std::string s="42";
int i=boost::lexical_cast<int>(s);

// float to string
float f=3.14151;
s=boost::lexical_cast<std::string>(f);

// literal to double
double d=boost::lexical_cast<double>("2.52");

// 失败的转换
s="Not an int";
try {
i=boost::lexical_cast<int>(s);
}
catch(boost::bad_lexical_cast& e) {
// 以上lexical_cast将会失败,我们将进入这里
}
}

这个例子仅仅示范了多种字面转换情形中的几种,我想你应该同意为了完成这些工作,通常你需要更多的代码。无论何时你不确定转换是否有效,都应该用一个try/catch?块来保护?lexical_cast?,就象你在这个例子看到的那样。你可能注意到了没有办法控制这些转换的格式;如果你需要这种级别的控制,你要用?std::stringstream

如果你曾经手工进行过类型间的转换,你应该知道,对于不同的类型,需要使用不同的办法来处理转换以及可能出现的转换失败。这不仅是有点不便而已,它还妨碍了用泛型代码执行转换的努力。稍后我们将看到?lexical_cast?如何帮助你实现这一点。

这个例子中的转换用手工来实现也非常简单,但可能会失去转型操作的美观和优雅。而?lexical_cast?做起来更简单,并且更美观。再考虑一下lexical_cast对与之一起工作的类型所需的简单要求。考虑到对所有符合该要求的类型的转换可以在一行代码内完成的事实。再结合该实现依赖于标准库的stringstream这一事实[15],你可以看到?lexical_cast?不仅是执行字面转换的便利方法,它更是C++编译艺术的一个示范。

[15]?事实上,对于某些转换,有一些优化的方法可以避免使用?std::stringstream?带来的额外开销。当然,你可以在需要的时候对你自己的类型定制它的行为。

用?lexical_cast?进行泛型编程

作为使用lexical_cast进行泛型编程的简单例子,来看一下如何用它创建一个?to_string?函数。这个函数接受任何类型的参数(当然它要符合要求)并返回一个表示该值的?string?。标准库的用法当然也可以在std::stringstream的帮助下用几行代码完成这个任务。在这里,我们使用lexical_cast?来实现,只需要一个前转换函数调用及一些错误处理。

#include <iostream>
#include <string>
#include "boost/lexical_cast.hpp"

template <typename T> std::string to_string(const T& arg) {
try {
return boost::lexical_cast<std::string>(arg);
}
catch(boost::bad_lexical_cast& e) {
return "";
}
}

int main() {
std::string s=to_string(412);
s=to_string(2.357);
}

这个小程序不仅易于实现,它还因为lexical_cast而增加了价值。

使类可以用于?lexical_cast

因为?lexical_cast?仅要求它所操作的类型提供适当的?operator<<?和?operator>>?,所以很容易为用户自定义类型增加字面转换的支持。一个可以同时作为lexical_cast的目标和源的简单UDT看起来就象这样:

class lexical_castable {
public:
lexical_castable() {};
lexical_castable(const std::string s) : s_(s) {};

friend std::ostream operator<<
(std::ostream& o, const lexical_castable& le);
friend std::istream operator>>
(std::istream& i, lexical_castable& le);

private:
virtual void print_(std::ostream& o) const {
o << s_ <<"\n";
}

virtual void read_(std::istream& i) const {
i >> s_;
}

std::string s_;
};

std::ostream operator<<(std::ostream& o,
const lexical_castable& le) {
le.print_(o);
return o;
}

std::istream operator>>(std::istream& i, lexical_castable& le) {
le.read_(i);
return i;
}

lexical_castable?类现在可以这样用了:

int main(int argc, char* argv[]) {
lexical_castable le;
std::cin >> le;

try {
int i = boost::lexical_cast<int>(le);
}
catch(boost::bad_lexical_cast&) {
std::cout << "You were supposed to enter a number!\n";
}
}

当然,输入和输出操作符最好可以允许这个类于于其它流。如果你使用标准库的IOStreams,或者其它使用?operator<<?和?operator>>的库,你可能已经有很多可以用于?lexical_cast?的类。它们不需要进行修改。直接对它们进行字面转换就行了!

总结

lexical_cast?是用于字符串与其它类型之间的字面转换的一个可重用及高效的工具。它是功能性和优雅性的结合,是杰出程序员的伟大杰作[16]。 不要在需要时实现小的转换函数,更不要在其它函数中直接插入相关逻辑,应该使用象?lexical_cast?这样的泛型工具。它有助于使代码更清晰,并让程序员专注于解决手上的问题。

[16]?我知道,我总是很傲慢的,我们这些程序员,工作中常常需要数学、物理学、工程学、建筑学,和其它一些艺术和学科。这会使人畏缩,但也有无穷的回报。

以下情况时使用lexical_cast:

读书人网 >操作系统

热点推荐