0

I have this class:

template<typename T> class Parser
{
    public:
        Parser() : count(0) {}
        virtual void parse(const string&);
        void get_token(void);
    private:
        T result;
        char token;
        string expression;
        int count;
};

now had the class not been generic, had the result been say, a double, I would have used this method to detect numbers.

while((strchr("1234567890.",token))
{
     /* add token to a "temp" string */
     /* etc. etc. */
}

result = atof(temp.c_str());

But since result is generic, I can't use any method like atof and atoi etc.

What do I do?

ApprenticeHacker
  • 21,351
  • 27
  • 103
  • 153

4 Answers4

6

Boost has this functionality built-in:

 #include <boost/lexical_cast.hpp>

 void Parser<T>::get_token() {
     std::string token = ...;
     result = boost::lexical_cast<T>(token);
 }

Add exception handling as required.


Or, perhaps you don't want to use Boost for some reason:

void Parser<T>::get_token() {
     std::string token = ...;

     std::stringstream ss;
     ss << token;
     ss >> result;
}

Check the error state of ss as required.


More expansive answers may be found on this related question, though it discusses only int specifically.

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • +1, Thanks. I'd rather not add boost to my project, so I'll go with `stringstream` – ApprenticeHacker Jan 07 '12 at 10:51
  • @IntermediateHacker: You only need a header. That's it. The `boost` solution is _far_ more robust. Please consider it again. – Lightness Races in Orbit Jan 07 '12 at 10:52
  • (If you're writing a parser, I'm baffled that you're not using Boost already!) – Lightness Races in Orbit Jan 07 '12 at 10:52
  • 1
    @IntermediateHacker: When writing a parser, I'd resort to a parser generator. Boost.Spirit is pretty awesome in that aspect. – Xeo Jan 07 '12 at 10:58
  • 3
    @Xeo Yes, I would have done that if I was like, building a parser for serious work, like a professional programming language / script etc. But I'm actually trying to learn how recursive descent parsers etc. are implemented. Therefore I think, writing from scratch would teach me more. – ApprenticeHacker Jan 07 '12 at 11:03
1

Another generic template based Numeric To String converter. It takes ints and doubles.

#include <sstream>
#include <iostream>
#include <string>
using namespace std;

template <class T>
inline std::string Numeric_To_String (const T& t)
{
    std::stringstream ss;
    ss << t;
return ss.str();
}


int main(int argc, char *argv[])
{
   int i = 9;
   double d = 1.2345;
   string s;

  cout <<"Generic Numeric_To_String( anyDatatype ) \n\n";

  s = Numeric_To_String( i );
  cout <<"int i to string    : "<< s <<"   "<< endl; 

  s = Numeric_To_String( d );
  cout <<"double d to string : "<< s <<"   "<< endl;
  cout <<" \n";   

  return 0;
}
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Software_Designer
  • 8,490
  • 3
  • 24
  • 28
0

With C++17 you can use the templated std::from_chars. https://en.cppreference.com/w/cpp/utility/from_chars

#include <charconv>
#include <iostream>

template <typename Number>
auto stringTo(std::string_view str)
{
    Number number;
    std::from_chars(str.data(), str.data() + str.size(), number);
    return number;
}

int main()
{
    const auto str = std::string("42");
    std::cout << stringTo<long>(str) << '\n';
    std::cout << stringTo<double>(str) << '\n'; 
}

Check the return value of std::from_chars to detect errors.

const auto result = std::from_chars(...);
if (result.ec == std::errc::invalid_argument || result.ec == std::errc::result_out_of_range)
{
   std::cout << "string to number error" << '\n';
}

More info and examples: https://www.bfilipek.com/2018/12/fromchars.html

GCC and clang don't yet support the floating point version of std::from_chars (August 2019).

Synck
  • 2,727
  • 22
  • 20
0

If you only have a hand full of types you want to parse, you can use template specialization:

template<>
void Parser<int>::parse(const string&)
{
    result = atoi(string.c_str());
}

template<>
void Parser<float>::parse(const string&)
{
    result = atof(string.c_str());
}

... But this only works if you implement every convertion you need, of course.

v01pe
  • 1,096
  • 2
  • 11
  • 19
  • Regarding `atoi` and `atof` - http://stackoverflow.com/questions/2892951/list-of-deprecated-c-functions. Also you need to use _named_ parameters; `string.c_str()` isn't going to work. – Lightness Races in Orbit Jan 07 '12 at 14:58