Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

So, we have int32_t, int16_t, uint64_t, etc.. But where are the atoi32, atoi16, atoui64, etc...?

Tags:

c++

c++11

I would like to convert a string input representing numbers to the respective numeric types. The problem is that I have strict type requirements, so, for instance, I cannot accept an x >= 2^15 where an int16_t value (signed) is expected.

How can I deal with this scenario, without writing all the conversion functions from scratch?

P.S.

Please, do not suggest boost::lexical_cast - I am using it already. The functions I am talking about are going to replace the default implementation of the lexical_cast template by means of the particular template specializations, namely:

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)
{
}
...

Ideally, it would be nice to have functions, like atoi32, atoi16, atoiu64, etc...

EDIT

I am using VS2010, so no luck with <cinttypes>.

Yes, it would be nice to have an improved atoi family of functions having the same error support as strtol.

EDIT2

Thought it was worthwhile to post my solution:

#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;
}

}

So, in the end I am using the strtol family of functions. Unfortunately, the guy who has suggested to use them has also deleted his post, I wonder why...

like image 695
mark Avatar asked Jan 23 '12 19:01

mark


1 Answers

The scanf family of <cstdio> functions implements all the required conversions, and <cinttypes> (in C++11; <inttypes.h> in a combined C++98 compiler with C99 library) defines the appropriate format string specifiers. E.g., to read in an int16_t from the C string s, do

int16_t i;
std::sscanf(s, "%"SCNd16, &i);
like image 147
Fred Foo Avatar answered Oct 14 '22 19:10

Fred Foo