Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::getline does not accept std::back_insert_iterator

Tags:

c++

stl

int main() { 
    std::deque<std::string> mydeque;
    std::back_insert_iterator<decltype(mydeque)> myback_insert_iterator(mydeque);
    std::ifstream myifstream("test.txt");
    while(std::getline(myifstream, *myback_insert_iterator)) {
    }
}

I simply want to read line-wise a text file into a string container. This produces compiler error:

C2784: could not deduce template argument for 'std::basic_istream<_Elem,_Traits> &' from 'std::ifstream'

What's wrong?

like image 419
Simon1X Avatar asked Jan 18 '23 05:01

Simon1X


2 Answers

Try:

int main()
{
    std::deque<std::string> mydeque;
    std::ifstream myifstream("test.txt");

    std::string line;
    while(std::getline(myifstream, line)
    {
        mydeque.push_back(line);
    }
}

If it is one word per line you can simplify to:

int main()
{
    std::deque<std::string> mydeque;
    std::ifstream myifstream("test.txt");

    // Note: istream_iterator<T> uses std::istream& operator>>(std::istream&, T&) to
    //       read data from the stream. If `T` is a std::string this means it will
    //       read a single space separated word.

    std::copy(std::istream_iterator<std::string>(myifstream),
              std::istream_iterator<std::string>(),
              std::back_inserter(mydeque)
             );
}

If each line contains multiple words and you want to use the back inserter then you need to define a class for reading a whole line in an object that can be used with iterators:

struct Line
{
    std::string data;
    operator std::string const&() const {return data;}

    friend std::istream& operator>>(std::istream& s, Line& dst)
    {
        return std::getline(s, dst.data);
    }
};

int main()
{
    std::deque<std::string> mydeque;
    std::ifstream myifstream("test.txt");

    std::copy(std::istream_iterator<Line>(myifstream),
              std::istream_iterator<Line>(),
              std::back_inserter(mydeque)
             );
}

Or we can just use the constructrs:

int main()
{
    std::ifstream myifstream("test.txt");
    std::deque<std::string> mydeque(std::istream_iterator<Line>(myifstream),
                                    (std::istream_iterator<Line>()));
    // Note: Extra brace required around second iterator here
    //       This is to avoid the problem with the `Most Vexing Parse`
    //       Which would otherwise make this a function declaration

}
like image 92
Martin York Avatar answered Jan 22 '23 09:01

Martin York


getline expects a string, not an output iterator. You can wrap myifstream into an input iterator and use std::copy. Like so:

#include <deque>
#include <fstream>
#include <algorithm>
#include <iterator>

int main() {
    std::deque<std::string> mydeque;
    std::back_insert_iterator<decltype(mydeque)> myback_insert_iterator(mydeque);
    std::ifstream myifstream("test.txt");
    std::istream_iterator<std::string> i_it(myifstream), eos;
    std::copy(i_it, eos, myback_insert_iterator);
}
like image 33
hc_ Avatar answered Jan 22 '23 10:01

hc_