Reputation: 22011
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?
Upvotes: 0
Views: 2686
Reputation: 3548
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).
Upvotes: 0
Reputation: 8587
Another generic template based Numeric To String converter. It takes int
s and double
s.
#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;
}
Upvotes: 1
Reputation: 1136
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.
Upvotes: 0
Reputation: 385194
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.
Upvotes: 6