I\'m writing part of program which parses and validates some user input in program console arguments. I choose to use stringstream for that purpose, but encounter a problem
A num_get
facet to support the explicit check for signedness. Rejects any non-zero number beginning with a '-'
(after white-spaces) for unsigned types and uses the default C locale's num_get
to do the actual conversion.
#include
#include
#include
#include
template >
class num_get_strictsignedness : public std::num_get
{
public:
typedef charT char_type;
typedef InputIterator iter_type;
explicit num_get_strictsignedness(std::size_t refs = 0)
: std::num_get(refs)
{}
~num_get_strictsignedness()
{}
private:
#define DEFINE_DO_GET(TYPE) \
virtual iter_type do_get(iter_type in, iter_type end, \
std::ios_base& str, std::ios_base::iostate& err, \
TYPE& val) const override \
{ return do_get_templ(in, end, str, err, val); } // MACRO END
DEFINE_DO_GET(unsigned short)
DEFINE_DO_GET(unsigned int)
DEFINE_DO_GET(unsigned long)
DEFINE_DO_GET(unsigned long long)
// not sure if a static locale::id is required..
template
iter_type do_get_templ(iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, T& val) const
{
using namespace std;
if(in == end)
{
err |= ios_base::eofbit;
return in;
}
// leading white spaces have already been discarded by the
// formatted input function (via sentry's constructor)
// (assuming that) the sign, if present, has to be the first character
// for the formatting required by the locale used for conversion
// use the "C" locale; could use any locale, e.g. as a data member
// note: the signedness check isn't actually required
// (because we only overload the unsigned versions)
bool do_check = false;
if(std::is_unsigned{} && *in == '-')
{
++in; // not required
do_check = true;
}
in = use_facet< num_get >(locale::classic())
.get(in, end, str, err, val);
if(do_check && 0 != val)
{
err |= ios_base::failbit;
val = 0;
}
return in;
}
};
Usage example:
#include
#include
int main()
{
std::locale loc( std::locale::classic(),
new num_get_strictsignedness() );
std::stringstream ss("-10");
ss.imbue(loc);
unsigned int ui = 42;
ss >> ui;
std::cout << "ui = "<
Notes:
1
in the ctorchar
, wchar_t
, charXY_t
), you need to add an own facet (can be different instantiations of the num_get_strictsignedness
template)"-0"
is accepted