Reputation: 3526
I'm using istream_iterator
to insert contents from my file. I use the std::copy
algorithm too.
So we know istream_iterator
takes a stream as an argument:
std::istream_iterator<int> it = file;
I can just pass the stream but why here doesn't it work?
#include <fstream>
#include <vector>
int main()
{
std::ifstream infile("in.txt");
std::vector<int> v;
std::copy(infile, std::istream_iterator<int>(), std::back_inserter(v));
}
I have to do it like this:
std::copy(std::istream_iterator<int>(infile), std::istream_iterator<int>(), std::back_inserter(v));
But this looks very verbose and I feel like they're a better way to do what I'm doing...
Upvotes: 1
Views: 161
Reputation: 96810
This is how the relevant overload of std::copy
is declared:
template< class InputIt, class OutputIt > OutputIt copy( InputIt first, InputIt last, OutputIt d_first );
This function is templatized and it will deduce the type by the argument given. In your case, the first argument is of type std::basic_ifstream<...>
, so since the second argument didn't match, you get a compile time error.
That's why you need to be explicit with the type. The compiler won't know what you mean otherwise.
A shorter way of doing this would be to provide the actual template argument explicitly:
v.assign<std::istream_iterator<int>>(infile, {});
Upvotes: 1
Reputation: 45675
The problem is what std::copy
expects from the object being passed. The algorithm std::copy
expects iterators to operate on. To be more precise, the first two arguments have to be "InputIterator"s to read from (start and end), that is, the two objects have to satisfy some "concept".
Sadly, IO streams in C++ don't fulfill the InputIterator concept automatically (also, an end iterator would still be missing), but only if you wrap them in an instance of std::istream_iterator<T>
, while the end iterator is symbolically defined using an instance without pointing to a stream.
You could wrap around std::copy
which accepts an input stream instead of two iterators (so this also eliminates the need to name the end iterator):
template <class T,
class OutputIt /* deduced */,
class CharT /* deduced */>
OutputIt copy_from_istream(std::basic_istream<CharT> & stream, OutputIt out) {
return std::copy(
std::istream_iterator<T, CharT>(stream),
std::istream_iterator<T>(),
out
);
}
Using this is now very simple:
copy_from_istream<int>(infile, std::back_inserter(v));
Upvotes: 2
Reputation: 1205
Try using vector::assign()
instead of copy()
algorithm:
v.assign(std::istream_iterator<int>(infile), std::istream_iterator<int>())
Upvotes: 0