std::istream_iterator to read whole lines?

M

Marcus Kwok

I am writing a program to read in a file, do some processing, then write
it out to a different file. I really like the idiom I use for output:

// std::vector<std::string> vec;
// std::eek:fstream out;
std::copy(vec.begin(),
vec.end(),
std::eek:stream_iterator<std::string>(out, "\n"));



Is there a way to do the same thing for input that will read whole
lines? I tried the obvious thing:

// std::ifstream in;
std::copy(std::istream_iterator<std::string>(in),
std::istream_iterator<std::string>(),
std::back_inserter(vec));

but it separates on whitespace so every word is a different element in
the vector. I would like it to do the same thing as

// std::string line;
while (std::getline(in, line)) {
vec.push_back(line);
}


It's not a big deal or anything. I would just like the the two
operations to look consistent.
 
N

Neil Cerutti

I am writing a program to read in a file, do some processing,
then write it out to a different file. I really like the idiom
I use for output:

// std::vector<std::string> vec;
// std::eek:fstream out;
std::copy(vec.begin(),
vec.end(),
std::eek:stream_iterator<std::string>(out, "\n"));



Is there a way to do the same thing for input that will read
whole lines? I tried the obvious thing:

// std::ifstream in;
std::copy(std::istream_iterator<std::string>(in),
std::istream_iterator<std::string>(),
std::back_inserter(vec));

but it separates on whitespace so every word is a different
element in the vector. I would like it to do the same thing as

// std::string line;
while (std::getline(in, line)) {
vec.push_back(line);
}

Implement a line-based input iterator. It should be a snap.

You could implement a line type instead, with a suitable
operator>>, but I don't like the idea as much.
 
M

Marcus Kwok

Neil Cerutti said:
Implement a line-based input iterator. It should be a snap.

OK, my template technique is not too strong yet, so here is what I came
up with. Basically, I copied the implementation of istream_iterator
from the STL that comes with VS .NET 2003 (I believe they still use
Dinkumware) but renamed some of the implementation items, and added a
specialization for std::string, so this may not be the simplest or most
elegant way. If anyone knows a simpler way to specialize
istream_iterator for std::string then please enlighten me. Also, please
disregard some of the funky spacing, as I'm trying to get it to fit on
80 character lines for the NG post.

#include <iostream>
#include <string>
#include <fstream>
#include <algorithm>
#include <vector>

template <class T,
class Ch = char,
class Tr = std::char_traits<Ch>,
class Dist = std::ptrdiff_t>
class my_istream_iterator : public std::iterator<std::input_iterator_tag,
T,
Dist,
const T*,
const T&> {
public:
typedef my_istream_iterator<T, Ch, Tr, Dist> my_t;
typedef Ch char_type;
typedef Tr traits_type;
typedef std::basic_istream<Ch, Tr> istream_type;

// construct singular iterator
my_istream_iterator() : my_istream(0) { }

// construct with input stream
my_istream_iterator(istream_type& s) : my_istream(&s) { getval(); }

// return designated value
const T& operator*() const { return my_val; }

// return pointer to class object
const T* operator->() const { return &**this; }

// preincrement
my_istream_iterator& operator++()
{
getval();
return *this;
}

// postincrement
my_istream_iterator operator++(int)
{
my_t tmp = *this;
++*this;
return tmp;
}

// test for iterator equality
bool equal(const my_t& rhs) const { return my_istream == rhs.my_istream; }

protected:
// get a T value if possible
void getval()
{
if (my_istream != 0 && !(*my_istream >> my_val))
my_istream = 0;
}

istream_type* my_istream; // pointer to input stream
T my_val; // lookahead value (valid if my_istream is not null)
};

// specialization for std::string
template <>
void my_istream_iterator<std::basic_string<char>, char,
std::char_traits<char>, std::ptrdiff_t>::getval()
{
if (my_istream != 0 && !(std::getline(*my_istream, my_val)))
my_istream = 0;
}

// my_istream_iterator template operators
// test for my_istream_iterator equality
template <class T, class Ch, class Tr, class Dist>
inline bool operator==(const my_istream_iterator<T, Ch, Tr, Dist>& lhs,
const my_istream_iterator<T, Ch, Tr, Dist>& rhs)
{
return lhs.equal(rhs);
}

template <class T, class Ch, class Tr, class Dist>
inline bool operator!=(const my_istream_iterator<T, Ch, Tr, Dist>& lhs,
const my_istream_iterator<T, Ch, Tr, Dist>& rhs)
{
return !(lhs == rhs);
}



int main(int argc, char* argv[])
{
std::ifstream in(argv[1]);
std::vector<std::string> vec;

std::copy(my_istream_iterator<std::string>(in),
my_istream_iterator<std::string>(),
std::back_inserter(vec));

std::eek:fstream out(argv[2]);
std::copy(vec.begin(),
vec.end(),
std::eek:stream_iterator<std::string>(out, "\n"));

return 0;
}

// vim: tabstop=4 shiftwidth=4
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top