Reputation: 3164
I am supposed to create a looks-like stream iterator class so that I can read from the input stream when incrmenting an object of my class.
I've done this:
template<class T>
struct istrm_it{
istrm_it() = default;
istrm_it(std::istream& in) :
in_(in), val_(T()) {
in_ >> val_;
}
T val_;
std::istream& in_ = std::cin;
istrm_it& operator++() { in >> val_; return *this; };
istrm_it& operator++(int) { in_ >> val_; return *this; };
T operator*() { return val_; }
bool operator==(const istrm_it& rhs)const { return in_ == rhs.in_; }
bool operator!=(const istrm_it& rhs) const{ return in_ != rhs.in_; }
};
int main(){
istrm_it<int> it(std::cin), e;
cout << *it << endl; // ok
it++; // ok read the next value from the nput stream
vector<int> vi;
while (it != e) // the problem here
vi.push_back(*it++);
for (auto i : vi)
std::cout << i << ", ";
std::cout << std::endl;
std::cout << std::endl;
}
What I get: Severity Code Description Project File Line Suppression State
Error C2678 binary '!=': no operator found which takes a left-hand operand of type 'std::istream' (or there is no acceptable conversion)
Upvotes: 3
Views: 102
Reputation: 3911
As @Some programmer dude
: Stream objects can neither be copied, assigned nor compared.
If you want to make it works for some educational purpose then you can add another member to your class istrm_iter
that keeps track of the stream state it is bound to and in in/equality operators compare there iterators whether their internal state is good or not so if both of them are good then they are equal and this occur when they are off-end
otherwise they are not equal:
The default constructor which doesn't bind the iterator to a stream should make the internal state bad.
And the ++
should check after each input operator whether the stream hits the EOF
or had reported an IO error thus it sets the status to bad. which makes it equal to the one constructed with default constructor (as off-the-end iterator).
Here is a simple suggestion:
template<class T>
struct istrm_it {
istrm_it() = default;
istrm_it(std::istream& in) :
in_(in), val_(T()),
is_good_(true) {
in_ >> val_;
}
bool is_good_ = false;
T val_ = T{};
std::istream& in_ = std::cin;
istrm_it& operator++() { in_ >> val_; if (!in_) is_good_ = false; return *this; };
istrm_it& operator++(int) { in_ >> val_; if (!in_) is_good_ = false; return *this; };
T operator*() { return val_; }
bool operator==(const istrm_it& rhs) const {
return is_good_ && rhs.is_good_ || !is_good_ && !rhs.is_good_;}
bool operator!=(const istrm_it& rhs) const{ return !(operator==(rhs)); }
};
and in main:
int main(){
istrm_it<int> it(std::cin), e;
cout << *it << endl;
vector<int> vi;
while (it != e)
vi.push_back(*it++);
for (auto i : vi)
std::cout << i << ", ";
std::cout << std::endl;
}
No it works. N.B This is just an example I know in real it takes a lot of stuff to mimick the class defined by the standard library.
Upvotes: 0
Reputation: 409166
The problem is in the comparison in_ != rhs.in_
(and in_ == rhs.in_
as well). You can't compare streams.
Instead you need to keep some kind of "is end iterator" or "is at end-of-file" state that is set when you reach end-of-file, and which is set by default in the default-constructed iterator object.
Upvotes: 7