Reputation:
I have a std::string
which could be a string or could be a value (such as 0
).
What is the best or easiest way to convert the std::string
to int
with the ability to fail? I want a C++ version of C#'s Int32.TryParse
.
Upvotes: 22
Views: 23381
Reputation: 224069
Before boost's lexical_cast
was available, I used to do the following:
namespace detail {
template< typename Target, typename Source >
struct stream_caster {
static Target stream_cast(const Source& s)
{
std::stringstream ss;
if( (ss << s).fail() ) {
throw std::bad_cast("could not stream from source");
}
Target t;
if( (ss >> t).fail() || !(ss >> ws).eof()) {
throw std::bad_cast("could not stream to target");
}
return t;
}
};
template< typename T >
struct stream_caster<T,T> {
static const T& stream_cast(const T& s)
{
return s;
}
};
template< typename Source >
struct stream_caster<std::string,Source> {
static std::string stream_cast(const Source& s)
{
std::ostringstream oss;
if( (oss << s).fail() ) {
throw std::bad_cast("could not stream from source");
}
return oss.str();
}
};
template< typename Target >
struct stream_caster<Target,std::string> {
static Target stream_cast(const std::string& s)
{
std::stringstream ss(s);
Target t;
if( (ss >> t).fail() || !(ss >> ws).eof()) {
throw std::bad_cast("could not stream to target");
}
return t;
}
};
template<>
struct stream_caster<std::string,std::string> {
static const std::string& stream_cast(const std::string& s)
{
return s;
}
};
}
template< typename Target, typename Source >
inline Target stream_cast(const Source& s)
{
return detail::stream_caster<Target,Source>::stream_cast(s);
}
Upvotes: 3
Reputation: 4016
The accepted answer is really a terrible answer for question as asked, as it violates the precept "use exceptions for exceptional cases".
Exceptions are an excellent tool for handling exceptional cases -- cases where something has genuinely gone wrong. They are poor tools for existing use-cases. Partly because throwing and catching an exception is expensive, and partly because it is misleading code -- when a developer sees an exception they should reasonably be able to assume something is going wrong there. Good discussions of this basic principle abound, but I like "The Pragmatic Programmer"'s, or this isn't bad: http://www.lohmy.de/2013/03/06/writing-use-cases-exception-or-alternate-flow/
boost::lexical_cast is an optimal solution when it really is an exception for it to be receiving a non-number.
If you are going through a string and want to do one thing if it's a number, and another if it's a number, don't use an exception for the boolean test. That's just bad programming.
In fact, boost offers try_lexical_convert, which is used in the implementation of lexical_cast (taken from the documentation here: http://www.boost.org/doc/libs/1_58_0/doc/html/boost_lexical_cast/synopsis.html#boost_lexical_cast.synopsis.lexical_cast).
template <typename Target, typename Source>
inline Target lexical_cast(const Source &arg)
{
Target result;
if (!conversion::try_lexical_convert(arg, result))
throw bad_lexical_cast();
return result;
}
Upvotes: 10
Reputation: 503855
Use boost::lexical_cast. If the cast cannot be done, it will throw an exception.
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
int main(void)
{
std::string s;
std::cin >> s;
try
{
int i = boost::lexical_cast<int>(s);
/* ... */
}
catch(...)
{
/* ... */
}
}
Without boost:
#include <iostream>
#include <sstream>
#include <string>
int main(void)
{
std::string s;
std::cin >> s;
try
{
std::stringstream ss(s);
int i;
if ((ss >> i).fail() || !(ss >> std::ws).eof())
{
throw std::bad_cast();
}
/* ... */
}
catch(...)
{
/* ... */
}
}
Faking boost:
#include <iostream>
#include <sstream>
#include <string>
template <typename T>
T lexical_cast(const std::string& s)
{
std::stringstream ss(s);
T result;
if ((ss >> result).fail() || !(ss >> std::ws).eof())
{
throw std::bad_cast();
}
return result;
}
int main(void)
{
std::string s;
std::cin >> s;
try
{
int i = lexical_cast<int>(s);
/* ... */
}
catch(...)
{
/* ... */
}
}
If you want no-throw versions of these functions, you'll have to catch the appropriate exceptions (I don't think boost::lexical_cast
provides a no-throw version), something like this:
#include <iostream>
#include <sstream>
#include <string>
template <typename T>
T lexical_cast(const std::string& s)
{
std::stringstream ss(s);
T result;
if ((ss >> result).fail() || !(ss >> std::ws).eof())
{
throw std::bad_cast();
}
return result;
}
template <typename T>
bool lexical_cast(const std::string& s, T& t)
{
try
{
// code-reuse! you could wrap
// boost::lexical_cast up like
// this as well
t = lexical_cast<T>(s);
return true;
}
catch (const std::bad_cast& e)
{
return false;
}
}
int main(void)
{
std::string s;
std::cin >> s;
int i;
if (!lexical_cast(s, i))
{
std::cout << "Bad cast." << std::endl;
}
}
Upvotes: 43
Reputation: 17997
The other answers that use streams will succeed even if the string contains invalid characters after a valid number e.g. "123abc". I'm not familiar with boost, so can't comment on its behavior.
If you want to know if the string contains a number and only a number, you have to use strtol:
#include <iostream>
#include <string>
int main(void)
{
std::string s;
std::cin >> s;
char *end;
long i = strtol( s.c_str(), &end, 10 );
if ( *end == '\0' )
{
// Success
}
else
{
// Failure
}
}
strtol returns a pointer to the character that ended the parse, so you can easily check if the entire string was parsed.
Note that strtol returns a long not an int, but depending on your compiler these are probably the same. There is no strtoi function in the standard library, only atoi, which doesn't return the parse ending character.
Upvotes: 10
Reputation: 96859
Another way using standard streams :
#include <sstream>
#include <iostream>
#include <string>
int main()
{
std::stringstream convertor;
std::string numberString = "Not a number!";
int number;
convertor << numberString;
convertor >> number;
if(convertor.fail())
{
// numberString is not a number!
std::cout << "Not a Number!";
}
}
Upvotes: 8