Maelstrom
Maelstrom

Reputation: 9

How to pass a different value than the end-of-stream default constructed istream_iterator?

1) How can I pass a different value than end-of-stream to functions like find_if(), sort(), or for_each()?

I don't manage to handle iterators, especially to use them in loops, it seems the way I try to browse the values is improper. What I'm trying to do with this code is to input some numbers with cin, to extract the even numbers with find_if, but to print the first three with for_each or any loop using those iterators. If I use another kind, there would be no purpose.

#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;
typedef istream_iterator<int> IIT;

int main()
{
    IIT iter(cin);
    IIT eos;
    auto even = [](int i){ return (i%2==0); };
    iter = find_if(iter, eos, even);
    //iter = find_if(iter, IIT(), even); //also works, it seems that ctor call of "IIT eof()" wasn't equivalent


    //auto print = [](IIT i){ cout << *i << " "; };
    //auto print = [](IIT i){ cout << *i << " "; return i; };
    //auto print = [](IIT i){ cout << *i << " "; return 0; };  //I don't know what I'm doing
    auto print = [](IIT i)->int { cout << *i << " "; return 0; };  //this doesn't help

    for_each(iter,eos,print); //no match for call to '(main()::<lambda(IIT)>) (const int&)'|

    for_each<IIT,IIT>(iter,eos,print); //no matching function for call to 'for_each(IIT&, IIT&, main()::<lambda(IIT)>&)'|
                                       //cannot convert 'print' (type 'main()::<lambda(IIT)>') to type 'std::istream_iterator<int>'|

    for(auto i : iter) cout << *i << " ";  //candidate: template<class _Tp, unsigned int _Nm> constexpr _Tp* std::begin(_Tp (&)[_Nm])|
                                           //template argument deduction/substitution failed:|
                                           //mismatched types '_Tp [_Nm]' and 'std::istream_iterator<int>'|
    return 0;
}

end-of-stream iterator

The default-constructed std::istream_iterator is known as the end-of-stream iterator. When a valid std::istream_iterator reaches the end of the underlying stream, it becomes equal to the end-of-stream iterator.

istream_iterator : default constructor

Constructs an end-of-stream istream iterator." [..] This kind of iterator has a special state as an end-of-stream iterator, which is acquired if an input operations fails (as returned by fail after an operation with the associated stream), and is also the resulting value of a default-constructed object.

stl_algo.h

  template<typename _InputIterator, typename _Function>
    _Function
    for_each(_InputIterator __first, _InputIterator __last, _Function __f)
    {
      // concept requirements
      __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
      __glibcxx_requires_valid_range(__first, __last);
      for (; __first != __last; ++__first)
    __f(*__first);
      return _GLIBCXX_MOVE(__f);
    }

Upvotes: 1

Views: 222

Answers (1)

AndyG
AndyG

Reputation: 41220

  1. std::for_each has template arguments template< class InputIt, class UnaryFunction > You are calling it like so: for_each<IIT, IIT>.

    Change this to for_each<IIT, decltype(print)> if you wish to use explicit template arguments (although I recommend letting the compiler infer the args via the parameters)

  2. Your print function is accepting an IIT, when in fact algorithms will dereference the iterators passed to it for the unary function, so it should accept an int instead:

    auto print = [](int i)->int { cout << i << " "; return 0; };
    
  3. for(auto i : iter) makes no sense; iter is an iterator type, not a range.

Upvotes: 0

Related Questions