2

I am learning C++ and am doing a project dealing with a class that represents rational numbers (such as ½). I have overloaded the istream >> operator so that it correctly reads rational numbers from the stream.

I am having an issue with taking in an integer into the stream for a rational number. For example if someone types 2 I want it to be read from the stream as 2/1. I have been told using the peek() function would work but I cannot figure out how. Here is the code:

std::istream& operator>>(std::istream& is, Rational& r)
{
  int p, q;
  char c;
  is >> p >> c >> q;

  if (!is)
    return is;

  // Require that the divider to be a '/'.
  if (c != '/') {
    is.setstate(std::ios::failbit);
    return is;
  }

  // Make sure that we didn't read p/0.
  if (q == 0) {
    is.setstate(std::ios::failbit);
    return is;
  }

  r = Rational(p, q);
  return is;
}

It works perfectly unless an integer is input; I want it to be read as (int)/1.

Any suggestions?

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Luciano
  • 27
  • 3
  • I don't understand you completely. Do you want `2` to be fine, as well as `2/1` but not `2/somethinginvalid`? – LogicStuff Feb 17 '16 at 01:21
  • If you think about it, you are performing 3 reads... so if you want someone to be able to input 1 item (such as just "2") or 3 items (such as "2" "/" "3") what you really need to do is read an entire line at once, and then parse it. – RyanP Feb 17 '16 at 01:29
  • Nice exercise to learn Boost.Spirit http://www.boost.org/doc/libs/1_63_0/libs/spirit/doc/html/spirit/qi/tutorials/complex___our_first_complex_parser.html – alfC Apr 14 '17 at 03:51

1 Answers1

4

It may help if you break is >> p >> c >> q; down, so you can check the state of the stream after each individual extraction (and do the peeking):

int p, q = 1; // default is 1

if(!(is >> p))
    ; // p is not good, handle it

if(is.peek() == '/')
{
    // there's an /
    is.ignore(1); // or is.get() to skip over it

    if(!(is >> q))
        ; // q is not good, handle it
}

// the following shall not be executed if extraction of q or p fails
r = Rational(p, q);

The variable c might not be needed. Also, if there's something like 1?, this will read 1, keep ? in the stream and you get 1/1. It's not so greedy (you can change that).

LogicStuff
  • 19,397
  • 6
  • 54
  • 74