Привет,
В некотором царстве, в некотором государстве, был сайт RSDN, а в нём форумы, а в форумах Исходники, а в Исходниках
постинг про atoiАвтор: orangy
Дата: 29.08.02
И закралась в голову шальная мысль, по аналогии со boost::lexical_cast (также смотри
stream_castАвтор: Igor Soukhov
Дата: 22.09.02
) сделать parse_cast.
Из этого получилось небольшое упражнение по шаблонам, которое и предлагаю на суд общественности.
Сознательно не положил сразу в Исходники, ибо мне хочется обсудить, доусовершенствовать и т.п. и т.д.
Прошу прощения также за комментарии на английском — привычка-с
Просьба помочь избавиться от: ret_val_adaptor и it_adaptor ( IT — regards

)
А также подсказать, где я ошибся, накосячил, перемудрил, недодумал и т.п. Спасибо заранее.
Проверено на MSVC7 и Intel6 — вроде работает.
#include <string>
#include <vector>
// Helper function to skip white space
template<typename It>
inline It skip_ws(It p)
{
while ((*p == ' ' || *p == '\t') && *(++p));
return p;
}
// just create typename for template argument and specialization
struct hex;
// Empty template, doesn't containt required info
// If someone will try to parse_cast to unknown type, error will be issued at compile time
template<typename C>
struct parser
{
/*
this is conversion result type
typedef **** return_type;
this is static function which parses input (iterator) and returns value
template<typename It>
static return_type process(It p)
*/
};
// specializations are pretty obvious, see also my post about atoi
template<>
struct parser<unsigned int>
{
typedef unsigned int return_type;
template<typename It>
static return_type process(It p)
{
p=skip_ws(p);
return_type val=0;
while (*p>='0' && *p<='9') { val*=10; val+=*p - '0'; ++p; }
return val;
}
};
template<>
struct parser<unsigned long>
{
typedef unsigned long return_type;
template<typename It>
static return_type process(It p)
{
p=skip_ws(p);
return_type val=0;
while (*p>='0' && *p<='9') { val*=10; val+=*p - '0'; ++p; }
return val;
}
};
template<>
struct parser<int>
{
typedef int return_type;
template<typename It>
static return_type process(It p)
{
p=skip_ws(p);
return_type val=0;
int sign=1;
sign*=(*p == '-' && (++p,true))?-1:((*p == '+' && (++p,true)),1);
while (*p>='0' && *p<='9') { val*=10; val+=*p - '0'; ++p; }
return val*sign;
}
};
template<>
struct parser<long>
{
typedef long return_type;
template<typename It>
static return_type process(It p)
{
p=skip_ws(p);
return_type sign=1, val=0;
sign*=(*p == '-' && (++p,true))?-1:((*p == '+' && (++p,true)),1);
while (*p>='0' && *p<='9') { val*=10; val+=*p - '0'; ++p; }
return val*sign;
}
};
// specialization for conversion from hex
// uses artificial type to distinguish from unsigned int
template<>
struct parser<hex>
{
typedef unsigned long return_type;
template<typename It>
static return_type process(It p)
{
p=skip_ws(p);
return_type val=0;
// skip 0x if any
if (*p == '0') if (*++p == 'x') ++p;
while ((*p>='0' && *p<='9') || (*p>='a' && *p<='f') || (*p>='A' && *p<='F'))
{
val*=16;
val+=(*p<='9')?(*p - '0'):((*p<='F')?(*p-'A'+10):(*p-'a'+10));
++p;
}
return val;
}
};
/* This adaptor is for MSVC, which won't understand the following declaration
*
* template<typename C, typename It>
* typename parser<C>::return_type parse_cast(It p);
* error C2039: 'return_type' : is not a member of 'parser<C>'
*
* May be someone can explain, why?
*/
template<typename C>
struct ret_val_adaptor
{
typedef parser<C>::return_type return_type;
};
// Adaptor for iterator, so we can specify conversion from non-iterators to suitable types
// In good compiler we could use partial specialization of parse_cast instead.
template<typename It>
struct it_adaptor
{
static const It &convert(const It &p) { return p; }
};
template<>
struct it_adaptor<std::string>
{
static const char* convert(const std::string &p) { return p.c_str(); }
};
template<typename C, typename It>
typename ret_val_adaptor<C>::return_type parse_cast(It p)
{
return parser<C>::process(it_adaptor<It>::convert(p));
}
int main()
{
// few tests to ensure correct function selection
unsigned int uival = parse_cast<unsigned int>("123");
int ival = parse_cast<int>("-2123");
unsigned int hexval = parse_cast<hex>("0xdeAdbEaf");
unsigned long ulval = parse_cast<unsigned long>("-2123");
long lval = parse_cast<long>(" -2123");
std::string test = "ff";
uival = parse_cast<hex>(test.begin());
std::string test2 = "-12";
std::vector<char> vc(test2.begin(), test2.end());
ival = parse_cast<int>(vc.begin());
lval = parse_cast<long>(test2);
}
RSDN@Home 1.0 alpha 12 (tester's build)