I can't understand the use of std::istream_iterator

2k Views Asked by At

I can't understand the code below.

(from https://www.boost.org/doc/libs/1_74_0/more/getting_started/unix-variants.html)

#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
    using namespace boost::lambda;
    typedef std::istream_iterator<int> in;

    std::for_each(
        in(std::cin), in(), std::cout << (_1 * 3) << " " );
}

The web page doesn't explain anything for the code.

What I can't understand is the line with std::for_each function.

std::for_each is defined as below.

template <class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function fn);

So first is in(std::cin), last is just in(), the function is the cout statement.

Could anyone explain to me the syntax of first and last syntax and meaning in the example code?

The first iterator seems to be constructed with initial value std::cin, but what's the use of in() for the last value?

I also can't understand the _1 part.

The program outputs 3 * any number of integer values I type in.

2

There are 2 best solutions below

1
On BEST ANSWER

Could anyone explain to me the syntax of first and last syntax and meaning in the example code?

The first iterator seems to be constructed with initial value std::cin, but what's the use of in() for the last value?

If you look at the description of the constructor of std::istream_iterator you can see that in() constructs the end-of-stream iterator.

istream_iterator(); //  < C++11
constexpr istream_iterator(); // > C++11

Constructs the end-of-stream iterator, value-initializes the stored value. This constructor is constexpr if the initializer in the definition auto x = T(); is a constant initializer (since C++11).

As for in(std::cin):

istream_iterator( istream_type& stream );
istream_iterator( const istream_iterator& other );  //< C++11
istream_iterator( const istream_iterator& other ) = default; // > C++11

Initializes the iterator, stores the address of stream in a data member, and performs the first read from the input stream to initialize the cached value data member.

source

And I also can't understand the _1 part.

What this does is to replace the placeholder _1 with every element in the iteration sequence and multiply it by 3, using the result in the output stream, as it should, given the unary function argument.

for_each(a.begin(), a.end(), std::cout << _1 << ' ');

The expression std::cout << _1 << ' ' defines a unary function object. The variable _1 is the parameter of this function, a placeholder for the actual argument. Within each iteration of for_each, the function is called with an element of a as the actual argument. This actual argument is substituted for the placeholder, and the “body” of the function is evaluated.

source

4
On

First a little explanation about the std::for_each function.

The function loops over a set of iterators, from the beginning to the end, calling a function for each element in the range.

If you have e.g. a vector of integers:

std::vector<int> v = { 1, 2, 3, 4 };

and want to print print them, then you could do:

std::for_each(v.begin(), v.end(), [](int val) { std::cout << val; });

The above call to std::for_each is equivalent to:

for (auto i = v.begin(); i != v.end(); ++i)
{
    std::cout << *i;
}

Now if we go the usage of the std::istream_iterator in the question, it is wrapping the input operator >> using iterators.

Rewriting the std::for_each call using standard C++ lambdas, it would look like this:

std::for_each(in(std::cin), in(), [](int value) { std::cout << (value * 3) << " " ); });

If we translate it to the "normal" for iterator loop then it becomes:

for (auto i = in(std::cin); i != in(); ++i)
{
    std::cout << (*i * 3) << " ";
}

What it does, is reading integer input (until end-of-file or an error) from std::cin, and then output the value multiplied by 3 and a space.


If you're wondering about in(std::cin) and in(), you have to remember that in is an alias for the type std::istream_iterator<int>.

That means in(std::cin) is the same as std::istream_iterator<int>(std::cin). I.e. it creates a std::istream_iterator<int> object, and passes std::cin to the constructor. And in() constructs an end-iterator object.

Making it even clearer, the code is equivalent to:

std::istream_iterator<int> the_beginning(std::cin);
std::istream_iterator<int> the_end;  // Default construct, becomes the "end" iterator

for (std::istream_iterator<int> i = the_beginning; i != the_end; ++i)
{
    int value = *i;  // Dereference iterator to get its value
                     // (effectively the same as std::cin >> value)

    std::cout << (value * 3) << " ";
}