Итак, у нас есть int32_t, int16_t, uint64_t и т. Д. Но где же находятся atoi32, atoi16, atoui64 и т. Д...?
Я хотел бы преобразовать строковый ввод, представляющий числа в соответствующие числовые типы. Проблема в том, что у меня есть строгие требования к типу, поэтому, например, я не могу принять x >= 2^15, где int16_t
значение (подписано) ожидается.
Как я могу справиться с этим сценарием, не написав все функции преобразования с нуля?
PS
Пожалуйста, не предлагайте 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
семейство функций. К сожалению, парень, который предложил использовать их, также удалил свой пост, интересно, почему...
1 ответ
scanf
семья <cstdio>
функции реализуют все необходимые преобразования, и <cinttypes>
(в C++11; <inttypes.h>
в комбинированном компиляторе C++98 с библиотекой C99) определяет соответствующие спецификаторы строки формата. Например, читать в int16_t
из строки C s
, делать
int16_t i;
std::sscanf(s, "%"SCNd16, &i);