Overloading operator>> to create array from string - c++

I would like to create an std::array from a std::string.
For this, I would like to overload the operator>>.
I have the following test case:
std::istream& operator>>(std::istream& is, const std::array<double, 3>& a)
{
char p1, p2;
is >> p1;
// if fail warn the user
for (unsigned int i = 1; i < a.size(); ++i)
{
// something to ignore/ check if numeric
}
is >> p2;
// if fail warn the user
return is;
}
int main()
{
std::string a = "[1 2 3]";
std::array<double, 3> arr;
std::istringstream iss (a);
iss >> arr;
return 0;
}
I would like for the operator to check if the characters [and ] are in the correct place and to construct the array with the elements inside.
How can I do checks if the extraction was successfull? How can I check the string between the parenthesis is numeric and if so construct my array from it?
Kind regards

I'd add a helper class that checks for a certain character in the stream and removes it if it's there. If it's not, sets the failbit.
Example:
#include <cctype>
#include <istream>
template <char Ch, bool SkipWhitespace = false>
struct eater {
friend std::istream& operator>>(std::istream& is, eater) {
if /*constexpr*/ (SkipWhitespace) { // constexpr since C++17
is >> std::ws;
}
if (is.peek() == Ch) // if the expected char is there, remove it
is.ignore();
else // else set the failbit
is.setstate(std::ios::failbit);
return is;
}
};
And it could then be used like this:
std::istream& operator>>(std::istream& is, std::array<double, 3>& a) {
// use the `eater` class template with `[` and `]` as template parameters:
return is >> eater<'['>{} >> a[0] >> a[1] >> a[2] >> eater<']'>{};
}
int main() {
std::string a = "[1 2 3]";
std::array<double, 3> arr;
std::istringstream iss (a);
// iss.exceptions(std::ios::failbit); // if you want exceptions on failure
if(iss >> arr) {
std::cout << "success\n";
} else {
std::cout << "fail\n";
}
}
Demo where , is used as separator in the input.

Related

Tokenize a std::string to a struct

Let's say I have the following string that I want to tokenize as per the delimiter '>':
std::string veg = "orange>kiwi>apple>potato";
I want every item in the string to be placed in a structure that has the following format:
struct pack_item
{
std::string it1;
std::string it2;
std::string it3;
std::string it4;
};
I know how to do it this way:
pack_item pitem;
std::stringstream veg_ss(veg);
std::string veg_item;
std::getline(veg_ss, veg_item, '>')
pitem.it1 = veg_item;
std::getline(veg_ss, veg_item, '>')
pitem.it2 = veg_item;
std::getline(veg_ss, veg_item, '>')
pitem.it3 = veg_item;
std::getline(veg_ss, veg_item, '>')
pitem.it4 = veg_item;
Is there a better and one-liner kind of way to do it?
Something like this:
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
std::string veg = "orange>kiwi>apple>potato";
typedef std::vector<std::string> it_vec;
int main(int argc, char* argv[]) {
it_vec vec;
std::stringstream veg_ss(veg);
std::string veg_item;
while (std::getline(veg_ss, veg_item, '>')) {
vec.push_back(veg_item);
}
for (const std::string& vec_item : vec) {
std::cout << vec_item << std::endl;
}
}
You don't need an intermediate variable.
pack_item pitem;
std::stringstream veg_ss(veg);
std::getline(veg_ss, pitem.it1, '>');
std::getline(veg_ss, pitem.it2, '>');
std::getline(veg_ss, pitem.it3, '>');
std::getline(veg_ss, pitem.it4, '>');
You might want to make that a function, e.g. operator >> (with a similar operator <<)
std::istream& operator >>(std::istream& is, pack_item & pitem) {
std::getline(is, pitem.it1, '>');
std::getline(is, pitem.it2, '>');
std::getline(is, pitem.it3, '>');
std::getline(is, pitem.it4, '>');
return is;
}
std::ostream& operator <<(std::ostream& os, pack_item & pitem) {
return os << pitem.it1 << '>'
<< pitem.it2 << '>'
<< pitem.it3 << '>'
<< pitem.it4 << '>';
}
int main() {
std::stringstream veg_ss("orange>kiwi>apple>potato>");
pack_item pitem;
veg_ss >> pitem;
}
Is there a better and one-liner kind of way to do it?
You can make a type who's >> reads in a string up to a delimiter, and read all four elements in one statement. Is that really "better"?
template <bool is_const>
struct delimited_string;
template<>
struct delimited_string<true> {
const std::string & string;
char delim;
};
template<>
struct delimited_string<false> {
std::string & string;
char delim;
};
delimited_string(const std::string &, char) -> delimited_string<true>;
delimited_string(std::string &, char) -> delimited_string<false>;
std::istream& operator >>(std::istream& is, delimited_string<false> s) {
return std::getline(is, s.string, s.delim);
}
template <bool is_const>
std::ostream& operator <<(std::ostream& os, delimited_string<is_const> s) {
return os << s.string << s.delim;
}
std::istream& operator >>(std::istream& is, pack_item & pitem) {
return is >> delimited_string { pitem.it1, '>' }
>> delimited_string { pitem.it2, '>' }
>> delimited_string { pitem.it3, '>' }
>> delimited_string { pitem.it4, '>' };
}
std::ostream& operator <<(std::ostream& os, const pack_item & pitem) {
return os << delimited_string { pitem.it1, '>' }
<< delimited_string { pitem.it2, '>' }
<< delimited_string { pitem.it3, '>' }
<< delimited_string { pitem.it4, '>' };
}
As suggested in the comments, you could use a for loop as such:
pack_item a;
std::array<std::reference_wrapper<std::string>, 4> arr{a.it1, a.it2, a.it3, a.it4};
constexpr std::string_view veg = "orange>kiwi>apple>potato";
std::istringstream ss(veg.data());
std::string str;
for(std::size_t idx = 0; std::getline(ss, str, '>'); ++idx){
arr[idx].get() = std::move(str);
}
If you meant "one-liner" in its true sense, then you could be nasty and use:
std::getline(std::getline(std::getline(std::getline(ss, a.it1, '>'), a.it2, '>'), a.it3, '>'), a.it4, '>');
Indeed:
#include <iostream>
#include <sstream>
#include <string>
struct pack_item
{
std::string it1;
std::string it2;
std::string it3;
std::string it4;
};
pack_item pack( const std::string & s )
{
pack_item p;
getline(getline(getline(getline(std::istringstream(s), p.it1,'>'), p.it2,'>'), p.it3,'>'), p.it4);
return p;
}
int main()
{
auto pitem = pack( "orange>kiwi>apple>potato" );
std::cout << pitem.it4 << "<" << pitem.it3 << "<" << pitem.it2 << "<" << pitem.it1 << "\n";
}
BTW, there is nothing wrong with multiple lines of code. The quest for the one-liner is often a distraction to doing things the Right Way™.
What I would do is to create a constructor with std::string_view as argument (the second, which is predefined, would be the separator), and use the find function.
The reason of using std::string_view is posted here: How exactly is std::string_view faster than const std::string&?
struct pack_item
{
std::string it1;
std::string it2;
std::string it3;
std::string it4;
pack_item():it1(){}
pack_item(std::string_view in, char sep = '>'){
auto ptr = in.begin();
auto l_ptr = ptr;
ptr = std::find(ptr, in.end(), sep);
it1 = std::string(l_ptr, ptr++);
l_ptr = ptr;
ptr = std::find(ptr, in.end(), sep);
it2 = std::string(l_ptr, ptr++);
l_ptr = ptr;
ptr = std::find(ptr, in.end(), sep);
it3 = std::string(l_ptr, ptr++);
l_ptr = ptr;
ptr = std::find(ptr, in.end(), sep);
it4 = std::string(l_ptr, ptr++);
}
};
You can see here that this can be easily converted into a loop if you want and stop it by checking:
if(ptr == in.end()) break;

how to read data from text file and store it into array in c++

I am trying to read the data from a text file and store it into array. I need it for solving FEM problem. Let's say my text file is as follows:
node: 1,2,3,4,5,6,7,8,9,10
x: 4,4,3.75,3.76773151,3,3.59192947,4,3.5,3.55115372,3.375, 3.71330586
y: 3,275,3,2.65921885,2.79192947,2.5,3,2.55115372,2.78349365,2.36222989
z: 0,0,0,0,0,0,0,0,0,0
I want to store this data from text file into a 10*4 matrix (myarray[10][4]). Also I need to store each column of this array into a vector. Let's say my vectors are:
double x[10];
double y[10];
double z[10];
for (int i = 0; i < 10; i++)
{
x[i] = myarray[i][1];
y[i] = myarray[i][2];
z[i] = myarray[i][3];
}
I wrote the code like this:
int main()
{
string line;
string coordinate[10][4];
ifstream mesh("mesh.txt");
for (int i = 0; i < 10; ++i)
{
for (int j = 0; j < 4; ++j)
{
if (getline(mesh, line, ';'))
{
coordinate[i][j] = line;
cout << coordinate[i][j] << endl;
cout << "mesh : " << line[0] << endl;
}
}
}
mesh.close();
}
Now my problem is when I want to put the each column of coordinate into a vector I get this error:
no suitable conversion function from string to double exist
I don't understand this error, and need help fixing it.
An iterative way may like this, use the splitter in a customized iterator class. It seems to be complicated but I think it's easy to maintain.
Note that the iterator class is a modified version of this great answer.
#include <fstream>
#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>
template <typename T>
class istream_line_iterator : public std::iterator<std::input_iterator_tag, T> {
std::istream* stream;
public:
// Creating from a stream or the end iterator.
istream_line_iterator(std::istream& s) : stream(&s) { dropLeadingSpace(); }
istream_line_iterator() : stream(nullptr) {}
// Copy
istream_line_iterator(istream_line_iterator const& copy)
: stream(copy.stream) {}
istream_line_iterator& operator=(istream_line_iterator const& copy) {
stream = copy.stream;
return *this;
}
// The only valid comparison is against the end() iterator.
// All other iterator comparisons return false.
bool operator==(istream_line_iterator const& rhs) const {
return stream == nullptr && rhs.stream == nullptr;
}
bool operator!=(istream_line_iterator const& rhs) const {
return !(*this == rhs);
}
// Geting the value modifies the stream and returns the value.
// Note: Reading from the end() iterator is undefined behavior.
T operator*() const {
T value;
(*stream) >> value;
return value;
}
T* operator->() const; // Not sure I want to implement this.
// Input streams are funny.
// Does not matter if you do a pre or post increment. The underlying stream
// has changed. So the effect is the same.
istream_line_iterator& operator++() {
dropLeadingSpace();
return *this;
}
istream_line_iterator& operator++(int) {
dropLeadingSpace();
return *this;
}
private:
void dropLeadingSpace() {
// Only called from constructor and ++ operator.
// Note calling this on end iterator is undefined behavior.
char c;
while ((*stream) >> std::noskipws >> c) {
if (c == '\n') {
// End of line. So mark the iterator as reaching end.
stream = nullptr;
return;
}
if (!std::isspace(c) && c != ',') {
// Found a non space character so put it back
stream->putback(c);
return;
}
}
// End of stream. Mark the iterator as reaching the end.
stream = nullptr;
}
};
int main() {
std::ifstream ifs("1.in");
std::string line;
std::vector<std::vector<double>> vec;
while (std::getline(ifs, line)) {
std::istringstream iss(line);
std::string pre;
iss >> pre;
std::vector<double> line_vec;
auto beg = istream_line_iterator<double>(iss);
auto end = istream_line_iterator<double>();
std::copy(beg, end, std::back_inserter(line_vec));
vec.push_back(std::move(line_vec));
}
for (const auto& inner : vec) {
for (auto d : inner) {
std::cout << d << ' ';
}
std::cout << std::endl;
}
return 0;
}

How to report custom istream failures

I would like to use operator>>() for reading linear algebraic data from console. I would like operator>>() to behave like it does for build-in data (like int, double), but I also wish to report appropriate messages when input cannot be parsed.
I’ve finally constructed a ‘custom_istream_failure’ class, but all together it was quite a hassle. Now I wonder: Is this the way to go, or does another mechanism exist for this purpose? Is this in the spirit of the standard?
I’ve included a small test program which reports a custom failure in the ‘expect’ function. Additionally I’ve included the ‘custom_istream_failure.h’ header file this question is about.
#include <iostream>
#include "custom_istream_failure.h"
struct vector_t { int x, y, z; };
bool expect(std::istream& is, char e)
{
if (is.get() != e)
{
custom_istream_failure(is)
<< "Expected '" << e << '\''
<< and_throw;
return false;
}
return true;
}
std::istream& operator>>(
std::istream& is, vector_t& v)
{
expect(is, '(') &&
(is >> v.x) &&
expect(is, ',') &&
(is >> v.y) &&
expect(is, ',') &&
(is >> v.z) &&
expect(is, ')');
return is;
}
int main()
{
try
{
std::cin.exceptions(std::istream::failbit);
vector_t vector;
std::cin >> vector;
}
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
return 0;
}
#ifndef CUSTOM_ISTREAM_FAILURE
#define CUSTOM_ISTREAM_FAILURE
#include <iostream>
#include <string>
#include <sstream>
class custom_istream_failure
: protected std::stringstream
{
public:
explicit custom_istream_failure(std::istream& is)
: m_is(is)
{}
custom_istream_failure& operator<<(
custom_istream_failure&
(*pf)(custom_istream_failure&))
{
return ((*pf)(*this));
}
#define CUSTOM_ISTREAM_FAILURE_SOP(D) \
custom_istream_failure& operator<<(D) \
{ \
*static_cast<std::stringstream*>(this) << v; \
return *this; \
}
CUSTOM_ISTREAM_FAILURE_SOP(bool v)
CUSTOM_ISTREAM_FAILURE_SOP(short v)
CUSTOM_ISTREAM_FAILURE_SOP(unsigned short v)
CUSTOM_ISTREAM_FAILURE_SOP(int v)
CUSTOM_ISTREAM_FAILURE_SOP(unsigned int v)
CUSTOM_ISTREAM_FAILURE_SOP(long v)
CUSTOM_ISTREAM_FAILURE_SOP(unsigned long v)
CUSTOM_ISTREAM_FAILURE_SOP(long long v)
CUSTOM_ISTREAM_FAILURE_SOP(unsigned long long v)
CUSTOM_ISTREAM_FAILURE_SOP(float v)
CUSTOM_ISTREAM_FAILURE_SOP(double v)
CUSTOM_ISTREAM_FAILURE_SOP(long double v)
CUSTOM_ISTREAM_FAILURE_SOP(void* v)
CUSTOM_ISTREAM_FAILURE_SOP(std::streambuf* v)
CUSTOM_ISTREAM_FAILURE_SOP(
std::ostream& (*v)(std::ostream&))
CUSTOM_ISTREAM_FAILURE_SOP(
std::ios& (*v)(std::ios&))
CUSTOM_ISTREAM_FAILURE_SOP(
std::ios_base& (*v)(std::ios_base&))
CUSTOM_ISTREAM_FAILURE_SOP(char v)
CUSTOM_ISTREAM_FAILURE_SOP(signed char v)
CUSTOM_ISTREAM_FAILURE_SOP(unsigned char v)
CUSTOM_ISTREAM_FAILURE_SOP(const char* v)
CUSTOM_ISTREAM_FAILURE_SOP(const signed char* v)
CUSTOM_ISTREAM_FAILURE_SOP(const unsigned char*v);
#undef CUSTOM_ISTREAM_FAILURE_SOP
private:
std::istream& m_is;
friend custom_istream_failure& and_throw(
custom_istream_failure&);
};
inline custom_istream_failure& and_throw(
custom_istream_failure& cif)
{
try { throw std::ios_base::failure(cif.str()); }
catch (...)
{
cif.m_is.setstate(std::ios::failbit, true);
}
return (cif);
}
#endif // CUSTOM_ISTREAM_FAILURE
One approach is to just make the input operator for your type handle the error conditions (example below). If a user wants exceptions to be thrown on error the setstate will trigger an appropriate exception. And for users that don't want exceptions will just check the status of the input stream in the usual manner.
std::istream &operator>>(std::istream &is, vector_t &v) {
char c;
if (is >> c && c == '(') {
int x = 0;
if (is >> x >> c && c == ',') {
int y = 0;
if (is >> y >> c && c == ',') {
int z = 0;
if (is >> z >> c && c == ')') {
v = {x, y, z};
return is;
}
}
}
}
is.setstate(std::ios_base::failbit);
return is;
}

Is there a way to stop std::cin when it encounters a `\n`

I've written code that works pretty well except for one thing. The task that I'm making this code for inputs data into the program as a whitespace seperated string of doubles. And their precicion may be larger than 10^-25. So I made my own class that can handle that.
The problem is, when I was writing the code, I was testing it by entering two values into the console by hand each time pressing enter so that my program can understand where one double ends and another starts (it was looking for a '\n' basically).
Now I really need to adapt this code to make i work with my task's input (whitespace seperated list of doubles like 2.521 32.12334656 23.21 .....). But I'm having a problem with getline in my overloaded >> operator. It simply eats the '\n' character and starts looking for more input. The only way I can get it to work is by manually enetering values and manually entering an additional whitespace after the last value and only then hit enter.
I'm asking for your help.
Here's the full code:
#include <iostream>
#include <string>
#include <algorithm>
class BigNumber {
private:
std::string fullPart;
std::string floatPart;
public:
BigNumber() : fullPart("0"), floatPart("0") {}
friend std::ostream & operator << (std::ostream & os, const BigNumber & bn);
friend std::istream & operator >> (std::istream & os, BigNumber & bn);
void operator+=(BigNumber & bn);
};
int main()
{
BigNumber bn, bntemp;
while (std::cin >> bntemp)
{
bn += bntemp;
if (std::cin.peek() == '\n')
break;
}
std::cout << bn << std::endl;
return 0;
}
void addFullPart(const std::string & add, std::string & add_to)
{
auto addConv = std::stold(add);
auto addToConv = std::stold(add_to);
auto newFull = std::to_string(addConv + addToConv);
add_to = std::string(newFull.begin(), std::find(newFull.begin(), newFull.end(), '.'));
}
bool carryReminder(std::string & add_to, int32_t indx_from)
{
for (auto curr = indx_from; curr >= 0; --curr)
{
if (add_to[curr] != '9')
{
++(add_to[curr]);
return true;
}
else
add_to[curr] = '0';
}
return false;
}
std::pair<std::string, int32_t> addFloatPart(std::string & add, std::string & add_to)
{
std::string resultFloat;
int32_t reminderReturn{};
// don't forget to reverse str
if (add.size() != add_to.size())
{
// add remaining 0's
if (add.size() < add_to.size())
{
while (add.size() != add_to.size())
{
auto tempBigger = add_to.back();
add_to.pop_back();
resultFloat.push_back(tempBigger);
}
}
else
{
while (add.size() != add_to.size())
{
auto tempBigger = add.back();
add.pop_back();
resultFloat.push_back(tempBigger);
}
}
}
// now they are equal and have a form of 120(3921) 595
for (int32_t i = add_to.size() - 1; i >= 0; --i)
{
int32_t add_toDigit = add_to[i] - '0';
int32_t addDigit = add[i] - '0';
if (add_toDigit + addDigit >= 10)
{
resultFloat.append(std::to_string((add_toDigit + addDigit) - 10));
// we have a remainder
if (i == 0 || !carryReminder(add_to, i - 1))
reminderReturn = 1;
}
else
{
resultFloat.append(std::to_string(add_toDigit + addDigit));
}
}
std::reverse(resultFloat.begin(), resultFloat.end());
return std::make_pair(resultFloat, reminderReturn);
}
std::ostream & operator<<(std::ostream & os, const BigNumber & bn)
{
os << bn.fullPart << "." << bn.floatPart;
return os;
}
std::istream & operator>>(std::istream & is, BigNumber & bn)
{
std::string temp;
std::getline(is, temp, ' ');
auto fullPartTemp = std::string(temp.begin(), std::find(temp.begin(), temp.end(), '.'));
auto floatPartTemp = std::string(std::find(temp.begin(), temp.end(), '.') + 1, temp.end());
bn.floatPart = floatPartTemp;
bn.fullPart = fullPartTemp;
return is;
}
void BigNumber::operator+=(BigNumber & bn)
{
auto pair = addFloatPart(bn.floatPart, floatPart);
floatPart = pair.first;
if (pair.second > 0)
addFullPart(std::to_string(std::stoi(bn.fullPart) + 1), fullPart);
else
addFullPart(bn.fullPart, fullPart);
}
I suggest that you first use getline to read a line. Then you can make an istringstream and use your >> on that. Specifically, you could add #include <sstream> and change the main function to the following:
int main()
{
BigNumber bn, bntemp;
std::string temp;
std::getline(std::cin, temp);
std::istringstream ln(temp);
while (ln.good()) {
ln >> bntemp;
bn += bntemp;
}
std::cout << bn << std::endl;
return 0;
}
Two changes are needed. In main
Discarded the peek approach. Too brittle.
int main()
{
BigNumber bn, bntemp;
std::string line;
std::getline(std::cin, line);
std::stringstream stream(line);
while (stream >> bntemp)
{
bn += bntemp;
}
std::cout << bn << std::endl;
return 0;
}
And in operator>>
std::istream & operator >> (std::istream & is, BigNumber & bn)
{
std::string temp;
// also do NOTHING if the read fails!
if (std::getline(is, temp, ' '))
{
// recommend some isdigit testing in here to make sure you're not
// being fed garbage. Set fail flag in stream and bail out.
auto floatPartTemp = std::string(temp.begin(), std::find(temp.begin(), temp.end(), '.'));
// if there is no . you are in for a world of hurt here
auto floatPartTemp = std::string(std::find(temp.begin(), temp.end(), '.') + 1, temp.end());
bn.floatPart = ;
bn.fullPart = fullPartTemp;
}
return is;
}
So it should probably look more like
std::istream & operator >> (std::istream & is, BigNumber & bn)
{
std::string temp;
if (std::getline(is, temp, ' '))
{
if (std::all_of(temp.cbegin(), temp.cend(), [](char ch) { return isdigit(ch) || ch == '.'; }))
{
auto dotpos = std::find(temp.begin(), temp.end(), '.');
bn.fullPart = std::string(temp.begin(), dotpos);
std::string floatPartTemp;
if (dotpos != temp.end())
{
floatPartTemp = std::string(dotpos + 1, temp.end());
}
bn.floatPart = floatPartTemp;
}
else
{
is.setstate(std::ios::failbit);
}
}
return is;
}
Perhaps you could then use
std::string temp;
is >> temp;
instead of std::getline().
If I remember well that breaks on spaces and keeps the newline in the buffer.

Convert string to int with bool/fail in C++

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.
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;
}
}
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.
Exceptions should not be used for boolean tests
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/
Use boost::lexical_cast if you always expect a number
boost::lexical_cast is an optimal solution when it really is an exception for it to be receiving a non-number.
Use boost::try_lexical_convert if non-numbers are part of your use case
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;
}
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!";
}
}
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);
}