In this section, we'll define a custom data structure and provide facilities to read such items from input streams as standard input:
- We need to include some headers first and for comfort, we declare that we use the std namespace by default:
#include <iostream>
#include <iomanip>
#include <string>
#include <algorithm>
#include <iterator>
#include <vector>
using namespace std;
- As a complex object example, we define a city structure. A city shall have a name, a population count, and geographic coordinates:
struct city {
string name;
size_t population;
double latitude;
double longitude;
};
- In order to be able to read such a city from a serial input stream, we need to overload the stream function operator>>. In this operator, we first skip all the leading whitespace with ws, because we do not want whitespace to pollute the city name. Then, we read a whole line of text input. This implies that in the input file, there is a whole text line only carrying the name of a city object. Then, after a newline character, a whitespace-separated list of numbers follows, indicating the population, the geographic latitude, and the longitude:
istream& operator>>(istream &is, city &c)
{
is >> ws;
getline(is, c.name);
is >> c.population
>> c.latitude
>> c.longitude;
return is;
}
- In our main function, we create a vector that can hold a range of city items. We fill it using std::copy. The input of the copy call is an istream_iterator range. By giving it the city struct type as a template parameter, it will use the operator>> function overload, which we just implemented:
int main()
{
vector<city> l;
copy(istream_iterator<city>{cin}, {},
back_inserter(l));
- In order to see whether our city parsing went right, we print what we got in the list. The I/O formatting, left << setw(15) <<, leads to the city name being filled with whitespace, so we get our output in a nicely readable form:
for (const auto &[name, pop, lat, lon] : l) {
cout << left << setw(15) << name
<< " population=" << pop
<< " lat=" << lat
<< " lon=" << lon << 'n';
}
}
- The text file from which we will feed our program looks like this. There are four example cities with their population count and geographical coordinates:
Braunschweig
250000 52.268874 10.526770
Berlin
4000000 52.520007 13.404954
New York City
8406000 40.712784 -74.005941
Mexico City
8851000 19.432608 -99.133208
- Compiling and running the program yields the following output, which is what we expected. Try to tamper around with the input file by adding some unnecessary whitespace before the city names in order to see how it gets filtered out:
$ cat cities.txt | ./initialize_complex_objects
Braunschweig population=250000 lat=52.2689 lon=10.5268
Berlin population=4000000 lat=52.52 lon=13.405
New York City population=8406000 lat=40.7128 lon=-74.0059
Mexico City population=8851000 lat=19.4326 lon=-99.1332