How to have a tuple as both the key and value of an unordered map using a hash function or boost?

Viewed 46

I am trying to use a tuple<string, string, string> that will be placed as both the key and value of the unordered map as such:

unordered_map < tuple<string, string, string>, tuple<string, string, string>, hash_tuple> songInfo;

I understand I'm supposed to define a hash function because C++ does not have a hasher for std::tuple. However, I'm struggling to implement this through the explanations I've been reading on the other stack overflow posts. This is what my code has so far:

#include <iostream>
#include <unordered_map>
#include <vector>
#include <fstream>
#include <tuple>



using namespace std;

typedef std::tuple<string, string, string> t;

struct hash_tuple : public unary_function <t, size_t> {
    size_t operator()(const t& x) const
{
    return get<0>(x) ^ get<1>(x) ^ get<2>(x);
}
};

typedef unordered_map <t, t, hash_tuple> songInfo;


int main() {
    string filePath = "../data/songInfo.txt";

    fstream songFile;
    songFile.open("songInfo.txt");

    string line;
    string name, artist, date, duration, genre, mood;
    vector <string> store;
    while (getline(songFile, line, ',')) { 
        store.push_back(line);
        tuple <string, string, string> iD(store[0], store[1], store[2]);
        tuple <string, string, string> info(store[3], store[4], store[5]);
        songInfo[iD] = info; 
    }
    for (auto it = songInfo.begin(); it != songInfo.end(); it++)
        cout << "[" << get<0>(it->first)  << ", " << get<1>(it->first)  << ", " << 
        get<2>(it->first)  << "] ==>" << get<0>(it->second)  << ", " << get<1>(it- 
        >second)  << ", " << get<2>(it->second)  << endl;

}

enter image description here

1 Answers

Okay "fixing" the problem is easy: you wanted to XOR-combine hashes, not strings:

struct hash_tuple {
    size_t operator()(const t& x) const {
        std::hash<std::string> h{};
        return h(get<0>(x)) ^ h(get<1>(x)) ^ h(get<2>(x));
    }
};

Note that using namespace std is frowned upon, using declarations trump typedefs and unary_function<> is deprecated. Next up there were some syntax errors.

Combining fixes for these: Live On Coliru

#include <fstream>
#include <iostream>
#include <tuple>
#include <unordered_map>
#include <vector>

using t = std::tuple<std::string, std::string, std::string>;

struct hash_tuple {
    size_t operator()(const t& x) const {
        std::hash<std::string> h{};
        return h(get<0>(x)) ^ h(get<1>(x)) ^ h(get<2>(x));
    }
};

using SongInfo = std::unordered_map<t, t, hash_tuple>;

int main() {

    std::string filePath = "songInfo.txt";

    std::fstream songFile;
    songFile.open("songInfo.txt");

    std::string         line;
    std::string         name, artist, date, duration, genre, mood;
    std::vector<std::string> store;

    SongInfo songInfo;
    while (getline(songFile, line, ',')) {
        store.push_back(line);
        std::tuple<std::string, std::string, std::string> iD(store[0], store[1], store[2]);
        std::tuple<std::string, std::string, std::string> info(store[3], store[4], store[5]);
        songInfo[iD] = info;
    }

    for (auto it = songInfo.begin(); it != songInfo.end(); it++)
        std::cout << "[" << get<0>(it->first) << ", " << get<1>(it->first)
                  << ", " << get<2>(it->first) << "] ==>" << get<0>(it->second)
                  << ", " << get<1>(it->second) << ", " << get<2>(it->second)
                  << std::endl;
}
Related