getline vs istream_iterator
I sometimes (depending on the situation) write a line class so I can use istream_iterator
:
#include <string>
#include <vector>
#include <iterator>
#include <iostream>
#include <algorithm>
struct Line
{
std::string lineData;
operator std::string() const
{
return lineData;
}
};
std::istream& operator>>(std::istream& str,Line& data)
{
std::getline(str,data.lineData);
return str;
}
int main()
{
std::vector<std::string> lines(std::istream_iterator<Line>(std::cin),
std::istream_iterator<Line>());
}
Reading to end of file with istream_iterator and istream overload
Regarding question #3, you could use a multimap instead of a vector.
First, assume you split your Order class up as follows:
class Customer{
public:
string name;
string address;
};
class Purchase {
public:
string product_name;
double unit_price;
int count;
Purchase() {}
Purchase(string pn, double up, int c) :product_name(pn), unit_price(up), count(c) {}
};
class Order {
Customer c;
std::vector<Purchase> p;
};
Now you can simply create a std::multimap<Customer, Purchase>
. Adding a customer/purchase pair does exactly what you want: If the customer doesn't already exist, he is added, otherwise the purchase is just added to the existing customer.
Of course, for this to work, you need to define a comparer as well. Simplest way might just be to define operator <
for the Customer
class. Implement it by comparing the name and disregarding the address.
As for your other questions, avoid mixing getline
and stream_iterator
s. It's not wrong per se, but it gets pretty tricky because getline reads a line at a time, and stream iterators just read to the next whitespace.
Honestly, the C++ IOStreams library is pretty awful to use in general. Since your data format is already cleanly line-separated already, I'd probably just ditch the stream iterators and use getline
everywhere.
Distance between istream_iterators
std::istream_iterator
is an InputIterator
, which means it only supports a single pass over the range you're iterating. There's no way to figure out the size, and then go back to the beginning to read the data.
You can read from std::cin
(or any other input stream) using std::copy
without knowing the size beforehand, just use std::back_inserter
to append the data being read to the vector
.
std::vector v;
std::copy( std::istream_iterator<std::string>(std::cin),
std::istream_iterator<std::string>(),
std::back_inserter(v) );
Is there a C++ iterator that can iterate over a file line by line?
EDIT: This same trick was already posted by someone else in a previous thread.
It is easy to have std::istream_iterator
do what you want:
namespace detail
{
class Line : std::string
{
friend std::istream & operator>>(std::istream & is, Line & line)
{
return std::getline(is, line);
}
};
}
template<class OutIt>
void read_lines(std::istream& is, OutIt dest)
{
typedef std::istream_iterator<detail::Line> InIt;
std::copy(InIt(is), InIt(), dest);
}
int main()
{
std::vector<std::string> v;
read_lines(std::cin, std::back_inserter(v));
return 0;
}
Related Topics
What Does the |= Operator Mean in C++
How to Use a Constexpr Value in a Lambda Without Capturing It
Undefined Reference to Symbol '_Zn5Boost6System15System_Categoryev' Error
Change Terminal Font Size with C++
G++ Ld: Symbol(S) Not Found for Architecture X86_64
Why Is '"Literal"' Encouraged to Decay to 'Const Char*' in C++ Argument Type Match
Adding Header and .Cpp Files in a Project Built with Cmake
_Attribute_((Constructor)) Call Order Confusion
Why Does This Work: Returning C String Literal from Std::String Function and Calling C_Str()
Read Qprocess Output to String
How to Invoke Pointer to Member Function When It's a Class Data Member
Dll Main on Windows VS. _Attribute_((Constructor)) Entry Points on Linux
Are There Tools That Help Organizing #Includes
In C++, Is There a Difference Between "Throw" and "Throw Ex"
What Is the Fastest Way to Compute Large Power of 2 Modulo a Number