Converting a string to various number formats I'm working on a set of PostgreSQL helper classes, and am representing each PostgreSQL data type as objects. Instead of creating a class for each number format, I've created a template so the user can create a Number&lt;int&gt;, Number&lt;double&gt; etc as necessary, which is awesome as it saves me lots of coding!

The problem I'm facing is I have the need to convert a string representing the value of the number (which is returned from libpq) to its relevant format (the fromString method). 


It's kinda messy.  Is there a neater solution than a lot of if / else's? 
I also have the problem that if the string doesn't contain type T, it causes an exception, so, to be safe, I'd have to wrap everything inside a try/catch making it even more messier! So, is there a way around doing this?




template &lt;typename T&gt;
class Number : public spg::datatypes::BaseDataType
{
public:
    Number() : BaseDataType(false) { checkTIsNumeric(); }
    Number(T val) : BaseDataType(false), val(val) { checkTIsNumeric(); }
    Number(const std::string&amp; s) : BaseDataType(false) { checkTIsNumeric(); fromString(s); }

    std::string toString() const { return std::to_string(val); }
    int getParamCount() { return 1; }

    T val;

protected:
    void parseString(std::vector&lt;std::string&gt;&amp; splitted)
    {
        // see http://www.cplusplus.com/reference/string/

        size_t hc = typeid(T).hash_code();

        // TODO maybe these should be wrapped inside try/catch because if string doesn't contain T, it will throw
        if (hc == typeid(int).hash_code())
            val = std::stoi(splitted[0]);
        else if (hc == typeid(double).hash_code())
            val = std::stod(splitted[0]);
        else if (hc == typeid(long double).hash_code())
            val = std::stold(splitted[0]);
        else if (hc == typeid(float).hash_code())
            val = std::stof(splitted[0]);
        else if (hc == typeid(long).hash_code())
            val = std::stol(splitted[0]);
        else if (hc == typeid(unsigned long).hash_code())
            val = std::stoul(splitted[0]);
        else if (hc == typeid(long long).hash_code())
            val = std::stoll(splitted[0]);
        else if (hc == typeid(unsigned long long).hash_code())
            val = std::stoull(splitted[0]);
    }

private:
    void checkTIsNumeric()
    {
        if (!std::is_arithmetic&lt;T&gt;::value || std::is_class&lt;T&gt;::value)
            throw "T is not numeric";
    }

};


I'm not sure if the checkTIsNumeric is necessary, as compilation will fail if a non numeric type is passed as T because std::to_string doesn't have a suitable overload.

I did a few tests using the giant if / else above, and using a std::stringstream. The latter was noticeably slower. E.g. in one benchmark, 14.0781s for the above code vs 19.6901s using std::stringstream.
First things first: Export all the things which are different for different types into a policy-class, like std::basic_string and many standard-library classes do.
The main advantage is being actually able to have types with different interfaces without running into compilation-errors or at least warnings:

template&lt;class T&gt;
struct standard_number_traits {
    static T parse(const std::string&amp; in) {
        T out;
        std::stringstream{in} &gt;&gt; out;
        return out;
    }
    using std::to_string;
};


Add specializations as needed for efficiency / versatility / correctness / fun.
Eliminate runtime-checks for having selected an acceptable type, powered by the prior change.
That also allows you to use the same basic C++ type with completely different IO-behavior:

template &lt;class T, class traits_type = standard_number_traits&lt;T&gt;&gt;
struct Number : spg::datatypes::BaseDataType
{
    Number(T val = T{}) : val(val) {}
    // Or is BaseDataType(false) not default-init?
    Number(const std::string&amp; s) : Number(traits_type::parse(s)) {}

    std::string toString() const { return traits_type::to_string(val); }
    int getParamCount() { return 1; }

    T val; // Shall that really be public? Well, might be ok.
};

Profit?