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...
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With