c++hashmapunordered-mapstdtuple

Using tuple in unordered_map


I want to use tuple consisting of int,char,char in my unordered_map. I am doing like this:

#include <string>
#include <unordered_map>
#include <cstring>
#include <iostream>
#include <tuple>

using namespace std;

tuple <int,char,char> kk;
unordered_map<kk,int> map;

int main()
{
    map[1,"c","b"]=23;
    return 0;
}

but this gives me following errors:

map.cpp:9:21: error: type/value mismatch at argument 1 in template parameter list     for ‘template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> class    std::unordered_map’
map.cpp:9:21: error:   expected a type, got ‘kk’
map.cpp:9:21: error: template argument 3 is invalid
map.cpp:9:21: error: template argument 4 is invalid
map.cpp:9:21: error: template argument 5 is invalid
map.cpp:9:26: error: invalid type in declaration before ‘;’ token
map.cpp: In function ‘int main()’:
map.cpp:14:16: error: assignment of read-only location ‘"b"[map]’

What I am doing wrong in this?


Solution

  • The template arguments for an unordered_map looks like this:

    template<
    
        class Key,
        class T,
        class Hash = std::hash<Key>,
        class KeyEqual = std::equal_to<Key>,
        class Allocator = std::allocator< std::pair<const Key, T> >
    > class unordered_map;
    

    std::hash is not specialized for tuples (scroll down to Standard specializations for library types). Therefore you need to provide your own, something like this:

    typedef std::tuple<int, char, char> key_t;
    
    struct key_hash : public std::unary_function<key_t, std::size_t>
    {
     std::size_t operator()(const key_t& k) const
     {
       return std::get<0>(k) ^ std::get<1>(k) ^ std::get<2>(k);
     }
    };
    // ..snip..
    typedef std::unordered_map<const key_t,data,key_hash,key_equal> map_t;
    //                                             ^ this is our custom hash
    

    And finally, as Benjamin Lindley answer already addresses, you need to use std::make_tuple:

    // d is data
    m[std::make_tuple(1, 'a', 'b')] = d;
    auto itr = m.find(std::make_tuple(1, 'a', 'b'));
    

    The code was grabbed from Using a std::tuple as key for std::unordered_map and here is the Live Example.