我使用boost lexical_cast库来经常将文本数据解析为数值。但是在几种情况下,我只需要检查值是否为数字;我实际上并不需要或使用转换。
所以,我正在考虑编写一个简单的函数来测试字符串是否为double:
template<typename T>
bool is_double(const T& s)
{
try
{
boost::lexical_cast<double>(s);
return true;
}
catch (...)
{
return false;
}
}
我的问题是,是否有任何优化编译器会在这里删除lexical_cast,因为我从未真正使用过该值?
有没有更好的技术来使用lexical_cast库来执行输入检查?
答案 0 :(得分:3)
现在,您可以使用标头boost/lexical_cast/try_lexical_convert.hpp
中现在定义的boost::conversion::try_lexical_convert
(如果您只想要try_lexical_convert
)。像这样:
double temp;
std::string convert{"abcdef"};
assert(boost::conversion::try_lexical_convert<double>(convert, temp) != false);
答案 1 :(得分:2)
由于强制转换可能会抛出异常,因此只会丢弃该强制转换的编译器会严重破坏。您可以假设所有主要编译器都能正确处理。
从性能的角度来看,尝试执行lexical_cast可能并不是最优的,但除非你以这种方式检查数百万个值,否则不必担心。
答案 2 :(得分:2)
我想你想稍微重写一下这个功能:
template<typename T>
bool tryConvert(std::string const& s)
{
try { boost::lexical_cast<T>(s);}
catch (...) { return false; }
return true;
}
答案 3 :(得分:1)
你可以尝试这样的事情。
#include <sstream>
//Try to convert arg to result in a similar way to boost::lexical_cast
//but return true/false rather than throwing an exception.
template<typename T1, typename T2>
bool convert( const T1 & arg, T2 & result )
{
std::stringstream interpreter;
return interpreter<<arg &&
interpreter>>result &&
interpreter.get() == std::stringstream::traits_type::eof();
}
template<typename T>
double to_double( const T & t )
{
double retval=0;
if( ! convert(t,retval) ) { /* Do something about failure */ }
return retval;
}
template<typename T>
double is_double( const T & t )
{
double retval=0;
return convert(t,retval) );
}
convert函数与boost :: lexical_cast基本相同,除了lexical cast更加小心避免使用固定缓冲区等来分配动态存储。
将boost :: lexical_cast代码重构为这种形式是可能的,但是代码非常密集且难以实现 - 恕我直言,遗憾的是lexical_cast没有使用像这样的东西来实现......然后它看起来像这样:
template<typename T1, typename T2>
T1 lexical_cast( const T2 & t )
{
T1 retval;
if( ! try_cast<T1,T2>(t,retval) ) throw bad_lexical_cast();
return retval;
}
答案 4 :(得分:0)
无论如何,编译器都不太可能设法抛弃转换。例外只是锦上添花。如果要优化它,则必须编写自己的解析器来识别float的格式。使用正则表达式或手动解析,因为模式很简单:
if ( s.empty() ) return false;
string::const_iterator si = s.begin();
if ( *si == '+' || * si == '-' ) ++ si;
if ( si == s.end() ) return false;
while ( '0' <= *si && *si <= '9' && si != s.end() ) ++ si;
if ( si == s.end() ) return true;
if ( * si == '.' ) ++ si;
if ( ( * si == 'e' || * si == 'E' )
&& si - s.begin() <= 1 + (s[0] == '+') + (s[0] == '-') ) return false;
if ( si == s.end() ) return si - s.begin() > 1 + (s[0] == '+') + (s[0] == '-');
while ( '0' <= *si && *si <= '9' && si != s.end() ) ++ si;
if ( si == s.end() ) return true;
if ( * si == 'e' || * si == 'E' ) {
++ si;
if ( si == s.end() ) return false;
if ( * si == '-' || * si == '+' ) ++ si;
if ( si == s.end() ) return false;
while ( '0' <= *si && *si <= '9' && si != s.end() ) ++ si;
}
return si == s.end();
未经测试......我将让您浏览所有可能的格式组合; v)
编辑:另请注意,这与本地化完全不兼容。没有转换,你绝对没有希望进行国际检查。
编辑2:哎呀,我以为别人已经建议了这个。 boost::lexical_cast
实际上看似简单。为了至少避免抛出+捕获异常,你可以稍微重新实现它:
istringstream ss( s );
double d;
ss >> d >> ws; // ws discards whitespace
return ss && ss.eof(); // omit ws and eof if you know no trailing spaces
另一方面,此代码已经过测试; v)
答案 5 :(得分:0)
最好先使用正则表达式,然后使用lexical_cast转换为实际类型。
答案 6 :(得分:0)
由于类型T是模板化的类型名称,我相信你的答案是正确的,因为它将能够处理已经由boost :: lexical_cast处理的所有情况。
不过,不要忘记专门针对已知类型的功能,例如char *
,wchar_t *
,std::string
,wstring
等。
例如,您可以添加以下代码:
template<>
bool is_double<int>(const int & s)
{
return true ;
}
template<>
bool is_double<double>(const double & s)
{
return true ;
}
template<>
bool is_double<std::string>(const std::string & s)
{
char * p ;
strtod(s.c_str(), &p) ; // include <cstdlib> for strtod
return (*p == 0) ;
}
这样,您可以“优化”所知类型的处理,并将剩余的案例委托给boost :: lexical_cast。