3

我经常使用 boost lexical_cast 库将文本数据解析为数值。然而,在某些情况下,我只需要检查值是否为数字;我实际上不需要或使用转换。

所以,我正在考虑编写一个简单的函数来测试字符串是否为双精度:

template<typename T> 
bool is_double(const T& s)
{
  try 
  {
    boost::lexical_cast<double>(s); 
    return true;
  }
  catch (...) 
  {
    return false;
  }
}

我的问题是,是否有任何优化编译器会在这里删除 lexical_cast,因为我从未真正使用过该值?

有没有更好的技术来使用 lexical_cast 库来执行输入检查?

4

7 回答 7

6

您现在可以使用boost::conversion::try_lexical_convert在标题中定义的 now boost/lexical_cast/try_lexical_convert.hpp(如果您只想要try_lexical_convert)。像这样:

double temp;
std::string convert{"abcdef"};
assert(boost::conversion::try_lexical_convert<double>(convert, temp) != false);
于 2015-05-13T13:10:06.107 回答
2

由于强制转换可能会引发异常,因此只会丢弃该强制转换的编译器将被严重破坏。您可以假设所有主要编译器都会正确处理此问题。

从性能的角度来看,尝试执行 lexical_cast 可能不是最佳的,但除非您以这种方式检查数百万个值,否则无需担心。

于 2010-02-12T05:07:13.647 回答
2

我认为您想稍微重写该函数:

template<typename T>  
bool tryConvert(std::string const& s) 
{ 
    try         { boost::lexical_cast<T>(s);} 
    catch (...) { return false; }

    return true; 
} 
于 2010-02-12T05:09:21.980 回答
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 基本相同,除了词法转换更小心地避免使用固定缓冲区等分配动态存储。

可以将 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;
}
于 2010-02-12T06:11:44.073 回答
0

无论如何,编译器都不太可能设法丢弃转换。例外只是锦上添花。如果要优化这一点,则必须编写自己的解析器来识别浮点数的格式。使用正则表达式或手动解析,因为模式很简单:

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)

于 2010-02-12T05:29:56.287 回答
0

最好先使用正则表达式,然后使用 lexical_cast 来转换为真实类型。

于 2010-02-12T06:11:57.623 回答
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。

于 2010-02-12T09:49:05.000 回答