简体   繁体   中英

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?

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;
}
  1. ss has type std::istream_iterator<std::string> .
  2. std::distance(ss, {}) computes the number of items between the first whitespace-delimited token in std::cin to the end of cin, effectively returning the number of whitespace-delimited tokens in std::cin. This is due to the way std::istream::operator>>(std::istream&, std::string&) functions (the second parameter is not actually an std::string , but I'm trying to keep this short). The default constructor for a std::istream_iterator<std::string> returns the end of any std::istream_iterator<std::string> .

The cutting of the contents of std::cin is actually done lazily when computing the distance.

That is indeed an interesting piece of code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM