0

I have the following code:

    std::istream_iterator<std::string> eos;              
    std::istream_iterator<std::string> iit (File);
    std::vector<std::string> result;
    std::copy(iit,eos,std::back_inserter(result));
    for(auto it=result.begin(); it!=result.end(); ++it )
        std::cout << *it << std::endl;

I am using iterators to read the contents of a File and store the result to my vector, I don't want to use any while or for loop, I want to do it using only any STL function, so I tried copy. The contents of the file is in the following form:

Pork bone:4
Pigs trotters:4
Loin of pork:4

The problem is that previous code reads each line until space or new line character, so my vector looks like:

Pork
bone:4
Pigs
trotters:4
Loin
of
pork:4

I want each line to be a new element in my vector, any idea how to solve this?

Avraam Mavridis
  • 8,698
  • 19
  • 79
  • 133

4 Answers4

2

It looks like there's an example in stack overflow already at How do I iterate over cin line by line in C++?

Quoting a relevant bit: "

class line {
    std::string data;
public:
    friend std::istream &operator>>(std::istream &is, line &l) {
        std::getline(is, l.data);
        return is;
    }
    operator std::string() const { return data; }    
};

For example, to read all the lines in a file into a vector of strings, you could use something like:

std::vector<std::string> lines;

std::copy(std::istream_iterator<line>(std::cin), 
          std::istream_iterator<line>(),
          std::back_inserter(lines));

" Disclaimer: I have not tried this myself, I'm just trusting Jerry Coffin based on his reputation etc.

Community
  • 1
  • 1
m24p
  • 664
  • 4
  • 12
1

You can create your own line-based iterator:

template<typename T>
class line_iterator
    : public std::iterator<std::input_iterator_tag, T>
{
public:
    typedef std::istream istream_type;
    typedef T value_type;

    line_iterator(istream_type& is) : ptr(&is) { getInput(); }
    line_iterator() : ptr(nullptr) { }

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

    line_iterator& operator++()
    {
        getInput();
        return *this;
    }

    T* operator->()
    {
        return &value;
    }

    line_iterator operator++(int)
    {
        line_iterator copy(*this);
        ++*this;
        return copy;
    }

    friend bool operator==(const line_iterator& lhs, const line_iterator& rhs)
    {
        return lhs.ptr == rhs.ptr;
    }

    friend bool operator!=(const line_iterator& lhs, const line_iterator& rhs)
    {
        return !(lhs == rhs);
    }
private:
    T value;
    istream_type* ptr;

    void getInput()
    {
        if (ptr)
        {
            if (!std::getline(*ptr, value)) ptr = nullptr;
        }
    }
};

Now you can simply do:

std::copy(line_iterator<std::string>(File),
          line_iterator<std::string>(), std::back_inserter(result));
David G
  • 94,763
  • 41
  • 167
  • 253
0

It seems there is no other way except to use std::getline and the same while loop.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

Instead of using istream_iterator, your best bet is probably to use the istream::getline function.

getline vs istream_iterator

http://www.cplusplus.com/reference/istream/istream/getline/

Community
  • 1
  • 1
StephenH
  • 1,126
  • 11
  • 24