0

I'm trying to understand operator overloading used in case of STL class templates, such as: map or pair.

Let me introduce you to my code:

#include <iostream> 
#include <iomanip>  // left, setw
#include <string> 
#include <map> 
#include <utility> // pair 
#include <algorithm> // count if
using namespace std; 

typedef pair <string, int> Emp; 
typedef map <string, Emp> MAP; 

class Zakr{
   int min, max; 
public: 
   Zakr(int min, int max): min(min), max(max){}

bool operator()(const pair<const string, Emp> &p) const{
    int wage = p.second.second; 
    return (min < wage) && (wage < max); 
}
}; 

void print (const MAP& m) {
   MAP::const_iterator it, fin = m.end(); 

for(it = m.begin(); it != fin; it++)
    cout << "Key:  " << left << setw(7) << it -> first
    << "Name:  " << setw(10) << it->second.first 
    << "Wage:  " << it->second.second << endl; 
}

int main(void){
   MAP emp; 

   MAP object; 

   emp["John"] = Emp("John K.", 1900); 
   emp["Tania"] = Emp("Tania L.", 1900); 
   emp["Jeremy"] = Emp("Jeremy C", 2100); 
   emp["Susie"] = Emp("Susie W.", 3100); 
   emp["Toto"] = Emp("Toto T.", 9900); 
   emp["Adrian"] = Emp("Adrian N.", 1600); 
   emp["Germy"] = Emp("Germy P.", 2600); 

 print(emp); 

 int mn = 0, mx = 2000; 
 int how_much = count_if(emp.begin(), emp.end(), Zakr(mn, mx)); 

 cout << how_much << " earn from" 
 << mn << " to " << mx << endl;
 }

I'm struggling to understand some bits, especially one in particular, i.e.:

class Zakr{
   int min, max; 
public: 
   Zakr(int min, int max): min(min), max(max){}

bool operator()(const pair<const string, Emp> &p) const{
    int wage = p.second.second; 
    return (min < wage) && (wage < max); 
}
}; 

So I build class called Zakr, so that I will be able to use it to determine as a functor in count_if statement.

Am I right ?

I initialize private fields, min and max to use them in constructor and than so that operator which has been overloaded could return the boolean value based on their own values. The most diffucult part is to understand bool operator overloading.

 bool operator()(const pair<const string, Emp> &p) const{
    int wage = p.second.second;

Why the hell I need to 1* make a pair of some useless string value and EMP?

Since all I'm interested in is stored in EMP, i.e.: int value which will be used in overloading is stored in Emp.

Why couldn't I just access int stored in Emp like so:

bool operator(Emp &p)
{
  int wage = p.second; 
  return (min < wage) && (wage < max); 
} 

Why I do I need to make another pair like so: (const pair &p), if all I'm interested in is values stored in pair called Emp.

Why do I need to make another pair with useless first element of above named pair: string. I'm not going to make use of it, so why it's needed to compile the code ?

I did try my best to explain my doubts as clear as its possible. Hopefully someone will understand this rather long post.

Cheers!

White Bear
  • 107
  • 1
  • 6

2 Answers2

2

This is because iterators over std::map return you a std::pair for each element. The first item in the pair is the map key, the second item is the map value. See the value_type in the documentation for std::map.

This question has some answers on how to get iterators over the map's values only.

Community
  • 1
  • 1
Thomas
  • 174,939
  • 50
  • 355
  • 478
  • Didn't know about this, I'm really glad it's so simple and that you've provided me with this easy to understand explanation. Thanks! – White Bear Sep 13 '14 at 16:59
0

1. Class Zakr:

Indeed, it's typically for use with count_if(). If you look at the link, you'll see count_if(first, last, pred) is equivalent to something like:

  int ret = 0;
  while (first!=last) {
    if (pred(*first)) ++ret;  // works as soon as object pred has operator() defined. 
    ++first;
  }
  return ret;

2. Why is a pair needed in operator():

A map works with pairs, each made of a unique key and a corresponding value.

This is in part hidden. For example, when you use a map as associative array with expression as emp["John"], the map will find the pair having the unique key "John" and return a reference to the corresponding value.

However, as soon as you iterate through the map, your iterator will address these pairs. Why ? Because if it would just iterate through the value, you would get value, but you would never know to which unique key it corresponds.

Consequence: count_if() iterates through the map, so the predicate is called with an iterator that addresses a pair.

3. Why make a useless pair:

First, the counting function does not create a dummy pair. It uses a reference to an existing pair (from performance point of view, it's no more cost than passing a pointer !)

And, well, the map is here to address general problems. You could one day be interested to make count not only on wage, but for example also on the associated key (example: all the wages no in the range for employees with name starting with 'A').

Christophe
  • 68,716
  • 7
  • 72
  • 138