To iterate over an input stream, we would usually use a std::istream_iterator like so:
typedef std::istream_iterator input_iterato
I attempted to pursue the idea of specializing std::begin and std::end for classes derived from std::basic_istream (I'm not so great at this template metaprogramming business):
namespace std
{
template
typename
std::enable_if<
std::is_base_of, C>::value,
std::istream_iterator>::type
begin(C& c)
{
return {c};
}
template
typename
std::enable_if<
std::is_base_of, C>::value,
std::istream_iterator>::type
end(C& c)
{
return {};
}
}
Actually, it works pretty well. I didn't create versions that take const C& because I don't think it makes sense to extract from a const stream (and I had errors when I tried to do so). I'm also not sure if I can make this more move friendly. So now I can print out the contents of myfile like so::
std::ifstream file("myfile");
std::copy(begin(file), end(file), std::ostream_iterator(std::cout, " "));
So these begin and end functions work as expected. However, it falls flat when used in a range-based for loop. std::basic_istream classes are derived from std::ios_base which already has a member called end (it's a flag for seeking within a stream). Once the range-based for loop finds this, it just gives up because it can't find a corresponding begin (not to mention that end is not the right kind of entity):
main.cpp:35:33: error: range-based ‘for’ expression of type ‘std::basic_ifstream’ has an ‘end’ member but not a ‘begin’
The only alternative that works in both situations, as others have mentioned, is to create a wrapper object. Unfortunately that end member in std::ios_base completely ruins any chance of implementing this in a nice way.