Итак, у нас есть int32_t, int16_t, uint64_t и т. Д. Но где же находятся atoi32, atoi16, atoui64 и т. Д ...? - PullRequest
5 голосов
/ 23 января 2012

Я хотел бы преобразовать строковый ввод, представляющий числа, в соответствующие числовые типы.Проблема в том, что у меня есть строгие требования к типу, поэтому, например, я не могу принять 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 Ответ

5 голосов
/ 23 января 2012

Семейство scanf функций <cstdio> реализует все необходимые преобразования, а <cinttypes> (в C ++ 11; <inttypes.h> в комбинированном компиляторе C ++ 98 с библиотекой C99) определяет соответствующую строку форматаспецификаторы.Например, чтобы прочитать int16_t из строки C s, сделайте

int16_t i;
std::sscanf(s, "%"SCNd16, &i);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...