我想将表示数字的字符串输入转换为相应的数字类型。问题是我有严格的类型要求,因此,例如,我不能接受 x> = 2 ^ 15 ,其中需要int16_t
值(签名)。
如果不从头开始编写所有转换函数,我该如何处理这种情况?
P.S。
请不要建议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
系列函数。不幸的是,那个建议使用它们的人也删除了他的帖子,我想知道为什么......
答案 0 :(得分:5)
scanf
系列<cstdio>
函数实现了所有必需的转换,<cinttypes>
(在C ++ 11中; <inttypes.h>
在组合的C ++ 98编译器中实现C99库)定义了适当的格式字符串说明符。例如,要从C字符串int16_t
中读取s
,请执行
int16_t i;
std::sscanf(s, "%"SCNd16, &i);