Search code examples
c++distanceistream-iterator

C++ count the number of words from standard input


I saw a piece of C++ code to count the number of words inputted from standard input:

#include <iostream>
#include <iterator>
#include <string>
using namespace std;

int main() {
    auto ss {
        istream_iterator<string>{cin}
    };
    cout << distance(ss, {}) << endl;

    return 0;
}

I have several questions:

  1. What's the type of auto ss?
  2. What does distance(ss, {}) do? Why does it calculate the number of words?

My guess is:

  1. istream_iterator<string>{cin} converts the standard input into the istream_iterator type, automatically separated by space (why?). Thus ss looks like a container with all words as its elements;
  2. distance(ss, {}) calculates the distance between the 1st element and the empty (thus outside of the last, but why?) element.

Can someone help me to go through my guess on this fantastic short piece of code?


Solution

  • auto ss deduces ss to be std::istream_iterator<std::string>, because that is what the full statement is constructing and assigning to ss.

    istream_iterator uses the specified istream's operator>> to read formatted input of the specified type, where operator>> reads input delimited by whitespace, including space characters, line breaks, etc. So, in this case, istream_iterator<string> is reading std::string values from std::cin one whitespace-delimited word at a time.

    istream_iterator is an input iterator, and a default-constructed istream_iterator denotes an end-of-stream iterator. When istream_iterator stops reading (EOF is reached, bad input is entered, etc), its value becomes equal to the end-of-stream iterator.

    std::distance() returns the number of elements in a range denoted by a pair of iterators. For a non-random input iterator, like istream_iterator, std::distance() iterates the range one element at a time via the iterator's operator++, counting the number of times it incremented the iterator, until the target iterator is reached. So, in this case, istream_iterator::operator++ internally reads a value from its istream, thus std::distance() effectively returns how many words are successfully read from std::cin until end-of-stream is reached.

    So, the code you have shown is roughly just an algorithmic way of writing the following equivalent loop:

    int main() {
        string s;
        size_t count = 0;
        while (cin >> s) {
            ++count;
        }
        cout << count << endl;
    
        return 0;
    }