【发布时间】:2012-01-23 19:39:24
【问题描述】:
我想将表示数字的字符串输入转换为相应的数字类型。问题是我有严格的类型要求,因此,例如,我不能接受 x >= 2^15 ,其中需要 int16_t 值(有符号)。
在不从头编写所有转换函数的情况下,如何处理这种情况?
附言
请不要建议boost::lexical_cast - 我已经在使用它了。我所说的函数将通过特定的模板特化来替换lexical_cast 模板的默认实现,即:
template<>
inline int32_t lexical_cast<int32_t,char const *>(const char * const & arg)
{
}
template<>
inline int16_t lexical_cast<int16_t,char const *>(const char * const & arg)
{
}
...
理想情况下,拥有atoi32、atoi16、atoiu64 等函数会很好......
编辑
我正在使用 VS2010,所以 <cinttypes> 运气不好。
是的,如果有一个改进的atoi 系列函数具有与strtol 相同的错误支持,那就太好了。
EDIT2
认为值得发布我的解决方案:
#pragma once
#include <boost/lexical_cast.hpp>
#include <limits>
namespace boost {
template<class TInt, class conv>
TInt atoi(conv f, const char *arg)
{
char* stop;
TInt res = f(arg, &stop, 10);
if (*stop)
{
throw_exception(bad_lexical_cast(typeid(TInt), typeid(const char *)));
}
return res;
}
template<class TInt>
typename std::enable_if<std::is_signed<TInt>::value, TInt>::type atoi(const char *arg)
{
char* stop;
long res = strtol(arg, &stop, 10);
if (*stop || std::numeric_limits<TInt>::min() > res || std::numeric_limits<TInt>::max() < res)
{
throw_exception(bad_lexical_cast(typeid(TInt), typeid(const char *)));
}
return (TInt)res;
}
template<class TInt>
typename std::enable_if<std::is_unsigned<TInt>::value, TInt>::type atoi(const char *arg)
{
char* stop;
unsigned long res = strtoul(arg, &stop, 10);
if (*stop || std::numeric_limits<TInt>::max() < res)
{
throw_exception(bad_lexical_cast(typeid(TInt), typeid(const char *)));
}
return (TInt)res;
}
template<> inline int8_t lexical_cast<int8_t,char const *>(const char * const & arg)
{
return atoi<int8_t>(arg);
}
template<> inline uint8_t lexical_cast<uint8_t,char const *>(const char * const & arg)
{
return atoi<uint8_t>(arg);
}
template<> inline int16_t lexical_cast<int16_t,char const *>(const char * const & arg)
{
return atoi<int16_t>(arg);
}
template<> inline uint16_t lexical_cast<uint16_t,char const *>(const char * const & arg)
{
return atoi<uint16_t>(arg);
}
template<> inline int32_t lexical_cast<int32_t,char const *>(const char * const & arg)
{
return atoi<int32_t>(strtol, arg);
}
template<> inline uint32_t lexical_cast<uint32_t,char const *>(const char * const & arg)
{
return atoi<uint32_t>(strtoul, arg);
}
template<> inline int64_t lexical_cast<int64_t,char const *>(const char * const & arg)
{
return atoi<int64_t>(_strtoi64, arg);
}
template<> inline uint64_t lexical_cast<uint64_t,char const *>(const char * const & arg)
{
return atoi<uint64_t>(_strtoui64, arg);
}
template<> inline double lexical_cast<double,char const *>(const char * const & arg)
{
char* stop;
double res = strtod(arg, &stop);
if (*stop)
{
throw_exception(bad_lexical_cast(typeid(double), typeid(const char *)));
}
return res;
}
template<> inline float lexical_cast<float,char const *>(const char * const & arg)
{
char* stop;
double res = strtod(arg, &stop);
if (*stop || -FLT_MAX > res || FLT_MAX < res)
{
throw_exception(bad_lexical_cast(typeid(float), typeid(const char *)));
}
return res;
}
}
所以,最后我使用的是strtol 系列函数。不幸的是,建议使用它们的人也删除了他的帖子,我想知道为什么......
【问题讨论】:
-
有strol和strtoll,strtoq。
-
有
atoi、atol、atoll,就够了,因为你提到的所有类型都可以转换为long long或int而不会出现溢出问题 -
那些是类型定义。如果你专门或重载 typedef,你会大吃一惊!
-
@mark,我可以问一下你想要这些功能的真正原因(除了漂亮)吗?
ato*家族在我看来总是很破碎,因为他们返回0合法的0和错误的输入。 -
你是对的。
strtol的错误支持应该被atoi系列函数所接受。