#include <iostream>
#include <map>

struct Data {
    int numFriends = 0, numAcquaintances = 0, numDates = 0;  // etc...
};

void print_tabbed(std::ostream& os, const Data& d)
{
    os << '\t' << d.numAcquaintances << " acquaintances\n";
    os << '\t' << d.numDates << " dates\n";
    os << '\t' << d.numFriends << " friends\n";
}

enum Country { USA, Canada, France };
enum Personality { Serious, Lazy, Funny };

class Religion {} *Islam = new Religion, *Hindu = new Religion;

class Person {
private:
    std::map<Country, Data> countryStats;
    std::map<Personality, Data> personalityStats;
    std::map<Religion*, Data> religionStats;

    // overloads
    std::map<Country, Data>&     statsMap(const Country&)     { return countryStats; }
    std::map<Personality, Data>& statsMap(const Personality&) { return personalityStats; }
    std::map<Religion*, Data>&   statsMap(const Religion*)    { return religionStats; }

public:
    template<typename T>
    void insert(const T& key, int Data::*dataPtr, int num) 
    {     
        statsMap(key)[key].*dataPtr += num; 
    }

    template<typename T>
    void insertData(const T& key, const Data& data) { statsMap(key)[key] = data; }

    template <typename map_type>
    void print_map(std::ostream& os, map_type& m, bool blank_line = true)
    {
        for (auto& e : m)
        {
            os << e.first << '\n';
            print_tabbed(os, e.second);
        }

        if (!m.empty() && blank_line)
            os << '\n';
    }

    void showAllStats() {  // for testing the results only (but only works for Country)
        print_map(std::cout, countryStats);
        print_map(std::cout, personalityStats);
        print_map(std::cout, religionStats, false);

        std::cout << '\n';
    }
};

int main() {
    Person bob, sam;

    bob.insert(USA, &Data::numFriends, 10);
    bob.insert(Canada, &Data::numFriends, 100);
    bob.insert(Canada, &Data::numDates, 5);
    sam.insert(USA, &Data::numFriends, 30);
    sam.insert(USA, &Data::numAcquaintances, 50);

    bob.insert (Funny, &Data::numAcquaintances, 20);  // won't compile
    sam.insert (Islam, &Data::numAcquaintances, 35);  // won't compile
    std::cout << "Bob:" << std::endl;  bob.showAllStats();  // correct results, but only for Country
    std::cout << "Sam:" << std::endl;  sam.showAllStats();
    std::cin.get();
}