We are going to define another structure like in the last recipe, but this time we are going to fill it into a map, which makes it more complicated because this container maps from keys to values instead of just holding all values in a list:
- First, we include all the needed headers and declare that we use the std namespace by default:
#include <iostream>
#include <iomanip>
#include <map>
#include <iterator>
#include <algorithm>
#include <numeric>
using namespace std;
- We want to maintain a little Internet meme database. Let's say a meme has a name, a description, and the year when it was born or invented. We will save them in an std::map, where the name is the key, and the other information is bunched up in a struct as the value associated with the key:
struct meme {
string description;
size_t year;
};
- Let's first ignore the key and just implement a stream operator>> function overload for struct meme. We assume that the description is surrounded by quotation marks, followed by the year. This would look like "some description" 2017 in a text file. As the description is surrounded by quotation marks, it can contain whitespace because we know that everything between the quotation marks belongs to it. By reading with is >> quoted(m.description), the quotation marks are automatically used as delimiters and dropped afterward. This is very convenient. Just after that, we read the year number:
istream& operator>>(istream &is, meme &m) {
return is >> quoted(m.description) >> m.year;
}
- OK, now we take the meme's name as the key for the map into account. In order to insert a meme into the map, we need an std::pair<key_type, value_type> instance. key_type is string, of course, and value_type is meme. The name is allowed to contain spaces too, so we use the same quoted wrapper as for the description. p.first is the name and p.second is the whole meme structure associated with it. It will be fed into the other operator>> implementation that we just implemented:
istream& operator >>(istream &is,
pair<string, meme> &p) {
return is >> quoted(p.first) >> p.second;
}
- Okay, that's it. Let's write a main function, which instantiates a map, and fill that map. Because we overloaded the stream function operator>>, istream_iterator can deal with this type directly. We let it deserialize our meme items from standard input and use an inserter iterator in order to pump them into the map:
int main()
{
map<string, meme> m;
copy(istream_iterator<pair<string, meme>>{cin},
{},
inserter(m, end(m)));
- Before we print what we have, let's first find out what's the longest meme name in the map. We use std::accumulate for this. It gets an initial value 0u (u for unsigned) and will visit the map element-wise in order to merge them together. In terms of accumulate, merging usually means adding. In our case, we want no numeric sum of anything, but the largest string length. In order to get that, we provide accumulate a helper function, max_func, which takes the current maximum size variable (which must be unsigned because string lengths are unsigned) and compares it to the length of the current item's meme name string, in order to take the maximum of both values. This will happen for each element. The accumulate function's final return value is the maximum meme name length:
auto max_func ([](size_t old_max,
const auto &b) {
return max(old_max, b.first.length());
});
size_t width {accumulate(begin(m), end(m),
0u, max_func)};
- Now, let's quickly loop through the map and print each item. We use << left << setw(width) to get a nice table-like printing:
for (const auto &[meme_name, meme_desc] : m) {
const auto &[desc, year] = meme_desc;
cout << left << setw(width) << meme_name
<< " : " << desc
<< ", " << year << 'n';
}
}
- That's it. We need a small Internet meme database file, so let's fill a text file with some examples:
"Doge" "Very Shiba Inu. so dog. much funny. wow." 2013
"Pepe" "Anthropomorphic frog" 2016
"Gabe" "Musical dog on maximum borkdrive" 2016
"Honey Badger" "Crazy nastyass honey badger" 2011
"Dramatic Chipmunk" "Chipmunk with a very dramatic look" 2007
- Compiling and running the program with the example meme database yields the following output:
$ cat memes.txt | ./filling_containers
Doge : Very Shiba Inu. so dog. much funny. wow., 2013
Dramatic Chipmunk : Chipmunk with a very dramatic look, 2007
Gabe : Musical dog on maximum borkdrive, 2016
Honey Badger : Crazy nastyass honey badger, 2011
Pepe : Anthropomorphic frog, 2016