Упражнение с templates
От: orangy Россия
Дата: 24.10.02 14:39
Оценка: 10 (1)
Привет,

В некотором царстве, в некотором государстве, был сайт 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)
"Develop with pleasure!"
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.