注:轉載請保證文章完整性
一、介紹
lexical_cast
是boost中一個非常有用,常用,好用的庫,我現在的小數據轉換用的都是lexical_cast
。 lexical_cast
最大的特點是安全,包括長度安全,類型安全。 下面我來介紹下lexical_cast
的基本使用方法。
Target lexical_cast(Source arg)
例如:
#include <boost/lexical_cast.hpp>
using namespace std;
using namespace boost;
int main() {
const double PI = 3.1415926535;
string str;
str = lexical_cast<string>(PI);
cout << str;
return 0;
}
非常容易吧,簡單也是他的優勢之一。
二、異常
lexical_cast
在執行失敗時會拋出異常bad_lexical_cast
上面的例子改為:
#include <boost/lexical_cast.hpp>
using namespace std;
using namespace boost;
int main() {
try {
string str = "3.1415926535";
double PI = lexical_cast<double>(str);
cout << PI;
return 0;
} catch( bad_lexical_cast& E ) {
cout << E.what() << endl;
}
}
當str為ABCD時, 無法轉成PI拋出異常 輸出
bad lexical cast: source type value could not be interpreted as target
三、一個小例子
為了加深大加理解 下面使用lexical_cast實現一個簡單的文本輸入是否為指定類型的小程序
#include <boost/lexical_cast.hpp>
#include <iostream>
using namespace std;
using namespace boost;
template<typename _T, typename _R>
bool isElement(_R r) {
try {
lexical_cast<_T>(r);
return true;
} catch(...) {
return false;
}
}
int main() {
try {
if( isElement<double>("3.14d159") )
cout << "YES" << endl;
else
cout << "NO" << endl;
} catch( bad_lexical_cast& E ) {
cout << E.what() << endl;
}
return 0;
}
測試結果:
測試:isElement<double>("3.14d159") 輸出:NO
測試:isElement<string>("3.14d159") 輸出:YES
測試:isElement<long>("314159") 輸出:YES
測試:isElement<long>("31.4159") 輸出:NO
測試:isElement<char>("314159") 輸出:NO
四、源碼分析
#ifdef BOOST_NO_STRINGSTREAM
#include <strstream>
#else
#include <sstream>
#endif
class bad_lexical_cast : public std::bad_cast {
public:
bad_lexical_cast() :
source( &typeid(void) ), target( &typeid(void) )
{
}
bad_lexical_cast( const std::type_info &s, const std::type_info &t ) :
source(&s), target(&t)
{
}
const std::type_info &source_type() const
{
return *source;
}
const std::type_info &target_type() const
{
return *target;
}
virtual const char *what() const throw()
{
return "bad lexical cast: "
"source type value could not be interpreted as target";
}
virtual ~bad_lexical_cast() throw()
{
}
private:
const std::type_info *source;
const std::type_info *target;
};
type_info的具體用法是:E.source_type().name()就可能到類型名。
核心轉換部分,用的是留的概念,從流內數據的剩余情況與流轉換成功與否情況來判斷操作是否成功。在不加域時這里就像一個黑盒子。
bool operator<<(const Source &input)
{
return !(stream << input).fail();
}
template<typename InputStreamable>
bool operator>>(InputStreamable &output)
{
return !is_pointer<InputStreamable>::value &&
stream >> output &&
(stream >> std::ws).eof();
}
bool operator>>(std::string &output)
{
#if defined(BOOST_NO_STRINGSTREAM)
stream << '\0';
#endif
output = stream.str();
return true;
}
僅提供該入口,具體實現被封在detail域里面。
template<typename Target, typename Source>
Target lexical_cast(Source arg)
{
detail::lexical_stream<Target, Source> interpreter;
Target result;
if(!(interpreter << arg && interpreter >> result))
throw_exception(bad_lexical_cast(typeid(Target), typeid(Source)));
return result;
}
最后, 我們可以發現
bad_lexical_cast(typeid(Target), typeid(Source)
與上面
bad_lexical_cast(const std::type_info &s, const std::type_info &t)
:source(&s), target(&t)
之間的區別,在我看來是寫倒了,不過不影響,也算是個不算bug的bug
五、總結
lexical_cast
是強大的,但不是萬能的,但在很多情況下他有著獨特的優點,安全方便快捷!!!