Custom Input and Output Operators for User-Defined Types
The is>>c input operator skips whitespace by default, so it stores the first non-whitespace character it finds.
Why Input Does Not Always Match Your Expectations
When a program reads input from a stream, the characters it receives are not always the ones it expects. Spaces, tabs, and newlines are all whitespace, and whether they get consumed or left in the stream depends on which input operation you use. Two operations that look almost identical can return different results for the same input. This article focuses on that difference, because it determines what your program actually sees when it reads a value.
The source introduces this idea in the context of user-defined types. When you write your own input operation, you decide how it reads from the stream. You must also know how the built-in operators behave, so that your code makes the same choices deliberately rather than by accident.
A Stream That Starts With Spaces
Imagine a stream whose first two characters are spaces, followed by the letter x. You want to read a single character from it into a variable named c. Before reading the explanation, make a prediction: which character will end up in c when you use the is>>c form, and which will end up in c when you use the is.get(c) form?
What do you think happens?
Given the stream " x" (two spaces then x), what does is>>c store in c?
Reveal answer
The letter x
The is>>c form skips leading whitespace by default, so it passes over both spaces and stores the first non-whitespace character it finds, which is x. The is.get(c) form, covered later in this article, behaves differently.
Tracing How is>>c Moves Through the Stream
The is>>c input operator skips whitespace by default, so it stores the first non-whitespace character it finds. The read position starts at the beginning of the stream. The operator moves past every space, tab, or newline it encounters. As soon as it reaches a character that is not whitespace, it stores that character in c. In the two-space example, the read position moves past both spaces, reaches x, and stores x.
The diagram above traces the read from start to finish. The whitespace is consumed, not stored. The operator does not hand you the spaces at all, which is why the variable holds a visible letter rather than a blank.
[x]- 1The string literal contains two spaces followed by x, which is the stream we are reading from.
- 2The is >> c operation begins at the start of the stream and skips leading whitespace by default.
- 3After skipping, it stores x in c, and the output shows [x] with no space inside the brackets.
- istringstream wraps the string " x" so it can be read like a stream
- is >> c skips the two leading spaces and stores the first non-whitespace character
- The brackets make the stored character visible in the output
Why Whitespace Skipping Is the Default
Formatted input is designed to read values that are separated by spacing and line breaks. Because is>>c skips whitespace by default, you can lay out your input across lines or add extra spaces between values without changing what the program reads. The operator treats whitespace as separation rather than as data, so the value you care about is the first real character it meets.
For each input operation you write, decide whether leading or surrounding whitespace is noise to be discarded or meaningful content to be kept. Make that choice on purpose, because the built-in default may not match what your data means.
Reading the Same Stream With is.get
The is.get(c) form is the contrasting case. It does not skip whitespace. It starts reading exactly at the current position, so it stores whatever character is next in the stream, including a space. Using the same two-space stream, the first character is a space, and is.get(c) stores that space rather than the x.
[ ]- 1The stream is the same as before: two spaces followed by x.
- 2
is.get(c)reads the character at the current position without skipping anything. - 3That character is a space, so c holds a space, and the output shows [ ] with the space inside the brackets.
is.get(c)does not skip whitespace- The stored character is the first space in the stream
- The output shows a space between the brackets
Whitespace Inside and Outside an Entry Name
The source describes an Entry input operator, a user-defined input operation for a type that holds a name. Its whitespace rule is specific: it ignores whitespace outside its name string, but it does not ignore whitespace within that string. In other words, spaces that surround the name are discarded as separators, while spaces that belong to the name itself are kept as part of the name.
Suppose an input record reads the text " Ada Lovelace " with extra spaces on both ends. Under the Entry rule described in the source, the leading and trailing spaces are ignored as separators, while the single space between Ada and Lovelace is kept, so the stored name is "Ada Lovelace". This example is an illustration of the stated rule rather than a reproduction of the source's code.
Mistakes When Mixing Whitespace Rules
Common mistake Assuming is.get(c) skips spaces the way is>>c does
What it looks likeReading from the stream " x" with is.get(c) and expecting x in c
Why it failsis.get(c)does not skip whitespace, so it stores whatever character is next, which here is a space.Do this insteadUse is>>c when leading whitespace should be skipped, and is.get(c) when every character, including spaces, must be read.
Common mistake Expecting every space in the input to disappear
What it looks likeAssuming an Entry name stored as "Ada Lovelace" will lose the space between its words
Why it failsThe Entry operator ignores whitespace outside its name string but not whitespace within it.
Do this insteadDecide which spaces are separators and which are part of the value, then design the operation to match.
Common mistake Choosing an input operator without checking what the surrounding whitespace means in the data
Looking Ahead to Pattern Matching
Reading one character at a time works when you know exactly what each position should contain. When you need to recognize a pattern across a stream of characters, the source points to a more systematic technique, regular expression matching. The source covers it in a later section and mentions it only as a pointer, so this article does not describe how it works.
For now, the useful takeaway is that character-by-character reading, with its whitespace rules, is the foundation that a pattern-recognition technique would build on. Understanding exactly which characters are consumed and which are stored is what makes later pattern work predictable.
Predict the Stored Character
A stream holds three characters: a tab, a newline, and then the letter q. For each of is>>c and is.get(c), state which character ends up in c and whether the tab and newline are consumed. Then explain the difference in one sentence.
Hints
- Ask whether the operator skips whitespace before it starts reading.
is.get(c)reads exactly the next character, which here is the tab.
Write a short paragraph describing an input record of your own design, such as a label followed by a value, and state for each part of the record whether surrounding whitespace should be discarded or kept.
Hints
- Separate the separators from the content.
- Consider whether a space that sits inside a value means the same thing as a space between values.
Key Takeaways
- The is>>c input operator skips whitespace by default and stores the first non-whitespace character it finds.
- The
is.get(c)form does not skip whitespace, so it stores whatever character is next, including a space. - The Entry input operator ignores whitespace outside its name string but not whitespace within it.
- Whitespace handling is a design decision for each input operation and must match what the data means.
- Regular expression matching is a later, more systematic technique for recognizing patterns in character streams, built on character-by-character reading.