Unordered Map with three unsigned chars as key [duplicate] - c++

This question already has answers here:
C++ unordered_map using a custom class type as the key
(7 answers)
Closed 8 years ago.
I have to make an unordered_map consisting of the following keys and value:
key: unsigned char, unsigned char, unsigned char
value: structure(int,int)
Here is my code to define that:
namespace G {
typedef std::tuple< unsigned char, unsigned char , unsigned char> key_t;
struct IndexGuide
{
int index;
int SerialNo;
};
typedef std::unordered_map<const key_t,IndexGuide> GuideDouble;
}
using namespace G;
Is there anything wrong in this code because when I link these files on linux terminal. It gives me errors.Some part of the error as follows
In function `std::__detail::_Hash_code_base const, std::pair const, G::IndexGuide>,
std::_Select1st const, G::IndexGuide> >,
std::equal_to
const>, std::hash const>, std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash,
false>::_M_bucket_index(std::__detail::_Hash_node const, G::IndexGuide>, false>
const*, unsigned int) const':

So your basic problem is that you don't have a hasher for std::tuple -- the standard library does not currently come with one by default. I think this is an oversight.
You cannot add a default hasher for std::tuple -- either for all tuples or for your particular list -- because the standard says you aren't allowed to:
17.6.4.2.1 Namespace std [namespace.std]/1 The behavior of a C++ program is undefined if it adds declarations or definitions to
namespace std or to a namespace within namespace std unless otherwise
specified. A program may add a template specialization for any
standard library template to namespace std only if the declaration
depends on a user-defined type and the specialization meets the
standard library requirements for the original template and is not
explicitly prohibited.
So this leaves you with either writing a custom hasher for your tuple type, and passing it to your unordered_map, or using a type that isn't merely std::tuple for your key, or writing a custom hasher that supports every tuple (including recursive tuples) while also supporting hash<T> lookup for non-tuples. A 4th option would be to write your own ADL-based hash system and set it up so that types with valid std::hash specializations use that, with various other fallbacks.
I will illustrate the 3rd option above.
First, you want to be able to combine two hash values in a way that doesn't lead to many spurious collisions.
inline std::size_t hash_result_combine(std::size_t lhs, std::size_t rhs)
{
return lhs ^( rhs + 0x9e3779b9 + (lhs<<6) + (lhs>>2));
}
this takes two hash outputs, and combines them. We can then chain this any number of times. (constants borrowed from https://stackoverflow.com/a/7111460/1774667 )
Next, some indexing boilerplate. Most generic work with std::tuple requires this stuff:
template<unsigned...>struct indexes{};
template<unsigned Max, unsigned... Is>struct make_indexes:make_indexes<Max-1,Max-1,Is...> {};
template<unsigned...Is>struct make_indexes<0,Is...>:indexes<Is...>{};
Finally, a hasher class that works with nearly every type:
struct my_hasher {
template<typename... Args>
std::size_t operator()(indexes<>, std::tuple<Args...> const& tup) const {
return 0;
}
template<unsigned I, unsigned... Is,typename... Args>
std::size_t operator()(indexes<I, Is...>,std::tuple<Args...> const& tup) const {
return hash_result_combine( (*this)(std::get<I>(tup)), (*this)(indexes<Is...>, tup) );
}
template<typename... Args>
std::size_t operator()(std::tuple<Args...> const& tup) const {
return (*this)(make_indexes<sizeof...(Args)>(), tup);
}
template<typename T>
std::size_t operator()(T const& t) const { return std::hash<T>()(t); }
};
you can pass my_hasher to an unordered_set in place of hash<T> for tuples, tuples containing tuples, or even for scalars -- it is very generous.
typedef std::unordered_map<const key_t,IndexGuide, my_hasher> GuideDouble;
and now we properly hash key_t.

You have to provide a hash function which tells std::unordered_map how to produce a hash value from your key_t. You can do it by specialization of hash template functor:
provide a Key:
struct Key{
unsigned char first;
unsigned char second;
unsigned char third;
bool operator==(const Key &other) const {
return (first == other.first
&& second == other.second
&& third == other.third);
}
};
specialize hash template:
namespace std {
template <>
struct hash< Key>
{
std::size_t operator()(const Key& k) const
{
using std::hash;
// Compute individual hash values for first,
// second and third and combine them using XOR
// and bit shifting:
return ((hash<char>()( k.first)
^ (hash<char>()( k.second) << 1)) >> 1)
^ (hash<int>()( k.third) << 1);
}
};
}
std::unordered_map< Key, IndexGuide> myMap;
As I said in comments, you can take a look at this SO thread.

unordered_set is implemented using a hash table.
in order to use unordered_set for a type that you defined you need to specialize the hash<> template for that type, as follows:
namespace std {
template <> struct hash<key_t>
{
size_t operator()(const key_t & t) const
{
// the logic for hashing
}
};
}

There is no default hasher for std::tuple.
You may use this code snippet Generic hash for tuples in unordered_map / unordered_set

Related

How do I use nested templates in c++?

I am new to C++ and doing a class in it now. As homework, we are supposed to write a function that accepts any container as input but does not use iterators. So we are not allowed to just pass std::begin(container) and std::end(container) as arguments. We have to pass the containers as references. My take on this was the following function declaration:
template <typename T, typename U, typename V, template <typename a, typename b> typename container>
void doStuff(container<T, U>& first, container<T, V>& second)
{
// the code
}
It accepts two containers (or any templated type that uses two template arguments). The second template argument in container is different since in arrays V might represent the size of the array and I want to be able to accept two arrays of different sizes.
Example:
std::array<bool, 4> a1 = { true, false, false, false };
std::array<bool, 1> a2 = { false };
Unfortunately, this example does not work. The error says that I doStuff does not accept arguments of these types. Why is that?
In my opinion, using a "templated template" here is important, because I would like to make sure that the function only accepts two containers if they contain the same kind of data. So passing an int array and a double array should not work.
If you want to support as many container types as possible, you should use the least restricting definition possible:
template <typename FirstContainer, typename SecondContainer>
void doStuff(FirstContainer& first, SecondContainer& second)
{
}
This is because container types come in all sort of flavors, e.g. std::array is a template taking a value type and a static size as argument, std::vector is a template taking a value type and an allocator, some custom StringList might not be a template at all.
Your implementation might have some specific requirements to the supported containers, e.g. it might only work for containers of integer types. But more often than not this is just an implicit result of the implementation. Take for a example a simple function summing up values of two containers:
template <typename FirstContainer, typename SecondContainer>
int sum(const FirstContainer& first, const SecondContainer& second)
{
int result = 0;
for (auto value : first)
result += value;
for (auto value : second)
result += value;
return result;
}
This function works fine with any value types that can be added to an integer. If it can't be added (like a std::string), it will cause a compilation error eventually.
(Note that one could write this function even more generic with an automatically deduced sum type instead of just int)
If these "implicit requirements" are not enough for you, you can add explicit checks using static_assert:
template <typename FirstContainer, typename SecondContainer>
int sum(const FirstContainer& first, const SecondContainer& second)
{
int result = 0;
for (auto value : first)
{
static_assert(std::is_same_v<int, decltype(value)>, "FirstContainer does not hold integers");
result += value;
}
for (auto value : second)
{
static_assert(std::is_same_v<int, decltype(value)>, "SecondContainer does not hold integers");
result += value;
}
return result;
}
Now your function is only accepting containers holding plain int, nothing else.
You can also use std::enable_if to completely "disable" your function for non-supported containers:
template <typename FirstContainer, typename SecondContainer>
auto sum(const FirstContainer& first, const SecondContainer& second)
-> std::enable_if_t<
std::is_same_v<typename FirstContainer::value_type, int> &&
std::is_same_v<typename SecondContainer::value_type, int>,
int
>
{
int result = 0;
for (auto value : first)
result += value;
for (auto value : second)
result += value;
return result;
}
Now your function is restricted to containers with a nested typedef value_type to type int.

How can I use C++11 variadic templates to define a vector-of-tuples backed by a tuple-of-vectors?

Suppose I have a bunch of vectors:
vector<int> v1;
vector<double> v2;
vector<int> v3;
all of the same length. Now, for every index i, I would like to be able to treat (v1[i], v2[i], v3[i]) as a tuple, and maybe pass it around. In fact, I want to have a a vector-of-tuples rather than a tuple-of-vectors, using which I can do the above. (In C terms, I might say an array-of-structs rather than a struct-of-arrays). I do not want to effect any data reordering (think: really long vectors), i.e. the new vector is backed by the individual vectors I pass in. Let's .
Now, I want the class I write (call it ToVBackedVoT for lack of a better name) to support any arbitrary choice of vectors to back it (not just 3, not int, double and int, not every just scalars). I want the vector-of-tuples to be mutable, and for no copies to be made on construction/assignments.
If I understand correctly, variadic templates and the new std::tuple type in C++11 are the means for doing this (assuming I don't want untyped void* arrays and such). However, I only barely know them and have never worked with them. Can you help me sketch out how such a class will look like? Or how, given
template <typename ... Ts>
I can express something like "the list of template arguments being the replacement of each typename in the original template arguments with a vector of elements of this type"?
Note: I think I might also want to later be able to adjoin additional vectors to the backing vectors, making an instance of ToVBackedVoT<int, double, int> into, say, an instance of ToVBackedVoT<int, double, int, unsigned int>. So, bear that in mind when answering. This is not critically important though.
One idea is to keep the storage in the "struct of array" style in form of vectors for good performance if only a subset of the fields are used for a particular task. Then, for each kind of task requiring a different set of fields, you can write a lightweight wrapper around some of those vectors, giving you a nice random access iterator interface similar to what std::vector supports.
Concerning the syntax of variadic templates, this is how a wrapper class (without any iterators yet) could look like:
template<class ...Ts> // Element types
class WrapMultiVector
{
// references to vectors in a TUPLE
std::tuple<std::vector<Ts>&...> m_vectors;
public:
// references to vectors in multiple arguments
WrapMultiVector(std::vector<Ts> & ...vectors)
: m_vectors(vectors...) // construct tuple from multiple args.
{}
};
To construct such a templated class, it's often preferred to have a template type deducting helper function available (similar to those make_{pair|tuple|...} functions in std):
template<class ...Ts> // Element types
WrapMultiVector<Ts...> makeWrapper(std::vector<Ts> & ...vectors) {
return WrapMultiVector<Ts...>(vectors...);
}
You already see different types of "unpacking" the type list.
Adding iterators suitable to your application (you requested in particular random access iterators) is not so easy. A start could be forward only iterators, which you might extend to random access iterators.
The following iterator class is capable of being constructed using a tuple of element iterators, being incremented and being dereferenced to obtain a tuple of element references (important for read-write access).
class iterator {
std::tuple<typename std::vector<Ts>::iterator...> m_elemIterators;
public:
iterator(std::tuple<typename std::vector<Ts>::iterator...> elemIterators)
: m_elemIterators(elemIterators)
{}
bool operator==(const iterator &o) const {
return std::get<0>(m_elemIterators) == std::get<0>(o.m_elemIterators);
}
bool operator!=(const iterator &o) const {
return std::get<0>(m_elemIterators) != std::get<0>(o.m_elemIterators);
}
iterator& operator ++() {
tupleIncrement(m_elemIterators);
return *this;
}
iterator operator ++(int) {
iterator old = *this;
tupleIncrement(m_elemIterators);
return old;
}
std::tuple<Ts&...> operator*() {
return getElements(IndexList());
}
private:
template<size_t ...Is>
std::tuple<Ts&...> getElements(index_list<Is...>) {
return std::tie(*std::get<Is>(m_elemIterators)...);
}
};
For demonstration purposes, two different patterns are in this code which "iterate" over a tuple in order to apply some operation or construct a new tuple with some epxression to be called per element. I used both in order to demonstrate alternatives; you can also use the second method only.
tupleIncrement: You can use a helper function which uses meta programming to index a single entry and advance the index by one, then calling a recursive function, until the index is at the end of the tuple (then there is a special case implementation which is triggered using SFINAE). The function is defined outside of the class and not above; here is its code:
template<std::size_t I = 0, typename ...Ts>
inline typename std::enable_if<I == sizeof...(Ts), void>::type
tupleIncrement(std::tuple<Ts...> &tup)
{ }
template<std::size_t I = 0, typename ...Ts>
inline typename std::enable_if<I < sizeof...(Ts), void>::type
tupleIncrement(std::tuple<Ts...> &tup)
{
++std::get<I>(tup);
tupleIncrement<I + 1, Ts...>(tup);
}
This method can't be used to assign a tuple of references in the case of operator* because such a tuple has to be initialized with references immediately, which is not possible with this method. So we need something else for operator*:
getElements: This version uses an index list (https://stackoverflow.com/a/15036110/592323) which gets expanded too and then you can use std::get with the index list to expand full expressions. The IndexList when calling the function instantiates an appropriate index list which is only required for template type deduction in order to get those Is.... The type can be defined in the wrapper class:
// list of indices
typedef decltype(index_range<0, sizeof...(Ts)>()) IndexList;
More complete code with a little example can be found here: http://ideone.com/O3CPTq
Open problems are:
If the vectors have different sizes, the code fails. Better would be to check all "end" iterators for equality; if one iterator is "at end", we're also "at end"; but this would require some logic more than operator== and operator!= unless it's ok to "fake" it in; meaning that operator!= could return false as soon as any operator is unequal.
The solution is not const-correct, e.g. there is no const_iterator.
Appending, inserting etc. is not possible. The wrapper class could add some insert or and / or push_back function in order to make it work similar to std::vector. If your goal is that it's syntactically compatible to a vector of tuples, reimplement all those relevant functions from std::vector.
Not enough tests ;)
An alternative to all the variadic template juggling is to use the boost::zip_iterator for this purpose. For example (untested):
std::vector<int> ia;
std::vector<double> d;
std::vector<int> ib;
std::for_each(
boost::make_zip_iterator(
boost::make_tuple(ia.begin(), d.begin(), ib.begin())
),
boost::make_zip_iterator(
boost::make_tuple(ia.end(), d.end(), ib.end())
),
handle_each()
);
Where your handler, looks like:
struct handle_each :
public std::unary_function<const boost::tuple<const int&, const double&, const int&>&, void>
{
void operator()(const boost::tuple<const int&, const double&, const int&>& t) const
{
// Now you have a tuple of the three values across the vector...
}
};
As you can see, it's pretty trivial to expand this to support an arbitrary set of vectors..
From asker's clarification on how this would be used (code that takes a tuple), I'm going to propose this instead.
//give the i'th element of each vector
template<typename... Ts>
inline tuple<Ts&...> ith(size_t i, vector<Ts>&... vs){
return std::tie(vs[i]...);
}
There's a proposal to allow parameter packs to be saved as members of classes (N3728). Using that, here's some untested and untestable code.
template<typename... Types>
class View{
private:
vector<Types>&... inner;
public:
typedef tuple<Types&...> reference;
View(vector<Types>&... t): inner(t...) {}
//return smallest size
size_t size() const{
//not sure if ... works with initializer lists
return min({inner.size()...});
}
reference operator[](size_t i){
return std::tie(inner[i]...);
}
};
And iteration:
public:
iterator begin(){
return iterator(inner.begin()...);
}
iterator end(){
return iterator(inner.end()...);
}
//for .begin() and .end(), so that ranged-based for can be used
class iterator{
vector<Types>::iterator... ps;
iterator(vector<Types>::iterator... its):ps(its){}
friend View;
public:
//pre:
iterator operator++(){
//not sure if this is allowed.
++ps...;
//use this if not:
// template<typename...Types> void dummy(Types... args){} //global
// dummy(++ps...);
return *this;
}
iterator& operator--();
//post:
iterator operator++(int);
iterator operator--(int);
//dereference:
reference operator*()const{
return std::tie(*ps...);
}
//random access:
iterator operator+(size_t i) const;
iterator operator-(size_t i) const;
//need to be able to check end
bool operator==(iterator other) const{
return std::make_tuple(ps...) == std::make_tuple(other.ps...);
}
bool operator!=(iterator other) const{
return std::make_tuple(ps...) != std::make_tuple(other.ps...);
}
};
You may use something like:
#if 1 // Not available in C++11, so write our own
// class used to be able to use std::get<Is>(tuple)...
template<int... Is>
struct index_sequence { };
// generator of index_sequence<Is>
template<int N, int... Is>
struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> { };
template<int... Is>
struct make_index_sequence<0, Is...> : index_sequence<Is...> { };
#endif
// The 'converting' class
// Note that it doesn't check that vector size are equal...
template<typename ...Ts>
class ToVBackedVoT
{
public:
explicit ToVBackedVoT(std::vector<Ts>&... vectors) : data(vectors...) {}
std::tuple<const Ts&...> operator [] (unsigned int index) const
{
return at(index, make_index_sequence<sizeof...(Ts)>());
}
std::tuple<Ts&...> operator [] (unsigned int index)
{
return at(index, make_index_sequence<sizeof...(Ts)>());
}
private:
template <int... Is>
std::tuple<const Ts&...> at(unsigned int index, index_sequence<Is...>) const
{
return std::tie(std::get<Is>(data)[index]...);
}
template <int... Is>
std::tuple<Ts&...> at(unsigned int index, index_sequence<Is...>)
{
return std::tie(std::get<Is>(data)[index]...);
}
private:
std::tuple<std::vector<Ts>&...> data;
};
And to iterate, create an 'IndexIterator' like the one in https://stackoverflow.com/a/20272955/2684539
To adjoin additional vectors, you have to create an other ToVBackedVoT as std::tuple_cat does for std::tuple
Conversion to a std::tuple of vectors (vector::iterators):
#include <iostream>
#include <vector>
// identity
// ========
struct identity
{
template <typename T>
struct apply {
typedef T type;
};
};
// concat_operation
// ================
template <typename Operator, typename ...> struct concat_operation;
template <
typename Operator,
typename ...Types,
typename T>
struct concat_operation<Operator, std::tuple<Types...>, T>
{
private:
typedef typename Operator::template apply<T>::type concat_type;
public:
typedef std::tuple<Types..., concat_type> type;
};
template <
typename Operator,
typename ...Types,
typename T,
typename ...U>
struct concat_operation<Operator, std::tuple<Types...>, T, U...>
{
private:
typedef typename Operator::template apply<T>::type concat_type;
public:
typedef typename concat_operation<
Operator,
std::tuple<Types..., concat_type>,
U...>
::type type;
};
template <
typename Operator,
typename T,
typename ...U>
struct concat_operation<Operator, T, U...>
{
private:
typedef typename Operator::template apply<T>::type concat_type;
public:
typedef typename concat_operation<
Operator,
std::tuple<concat_type>,
U...>
::type type;
};
// ToVectors (ToVBackedVoT)
// =========
template <typename ...T>
struct ToVectors
{
private:
struct to_vector {
template <typename V>
struct apply {
typedef typename std::vector<V> type;
};
};
public:
typedef typename concat_operation<to_vector, T...>::type type;
};
// ToIterators
// ===========
template <typename ...T>
struct ToIterators;
template <typename ...T>
struct ToIterators<std::tuple<T...>>
{
private:
struct to_iterator {
template <typename V>
struct apply {
typedef typename V::iterator type;
};
};
public:
typedef typename concat_operation<to_iterator, T...>::type type;
};
int main() {
typedef ToVectors<int, double, float>::type Vectors;
typedef ToVectors<Vectors, int, char, bool>::type MoreVectors;
typedef ToIterators<Vectors>::type Iterators;
// LOG_TYPE(Vectors);
// std::tuple<
// std::vector<int, std::allocator<int> >,
// std::vector<double, std::allocator<double> >,
// std::vector<float, std::allocator<float> > >
// LOG_TYPE(Iterators);
// std::tuple<
// __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >,
// __gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >,
// __gnu_cxx::__normal_iterator<float*, std::vector<float, std::allocator<float> > > >
}
As an alternative similar to boost::zip_iterator I wrote a zip function with a very simple interface:
vector<int> v1;
vector<double> v2;
vector<int> v3;
auto vec_of_tuples = zip(v1, v2, v3);
For example, iterate over these tuples:
for (auto tuple : zip(v1, v2, v3)) {
int x1; double x2; int x3;
std::tie(x1, x2, x3) = tuple;
//...
}
Here, zip() takes any number of ranges of any type. It returns an adaptor which can be seen as a lazily evaluated range over a tuple of elements originating from the wrapped ranges.
The adaptor is part of my Haskell-style functional library "fn" and implemented using variadic templates.
Currently it doesn't support modification of the original ranges' values via the adaptor because of the design of the library (it's intended to be used with non-mutable ranges like in functional programming).
A brief explanation on how this is done is: zip(...) returns an adaptor object which implements begin() and end(), returning an iterator object. The iterator holds a tuple of iterators to the wrapped ranges. Incrementing the iterator increments all wrapped iterators (which is implemented using an index list and unpacking an incrementing expression into a series of expressions: ++std::get<I>(iterators)...). Dereferencing the iterator will decrement all wrapped iterators and pass it to std::make_tuple (which is also implemented as unpacking the expression *std::get<I>(iterators)...).
P.S. Its implementation is based on a lot of ideas coming from answers to this question.

How to make boost unordered_map to support flyweight<string>

I am trying to do the following:
boost::unordered_map<boost::flyweight<std::string>, boost::flyweight<std::string> > map;
boost::flyweight<std::string> foo(name);
map[foo] = foo;
But the compiler complains:
"error C2665: 'boost::hash_value' : none of the 17 overloads could convert all the argument types".
But I have defined the following function:
std::size_t hash_value(const boost::flyweight<std::string> & b)
{
boost::hash<std::string> hasher;
const std::string & str = b.get();
return hasher(str);
}
bool operator==(const boost::flyweight<std::string>& f, const boost::flyweight<std::string> & second)
{
return f.get() == second.get();
}
But it doesn´t compile.
What do I need to do to make boost unordered_map to support flyweight?
[EDIT]
I got it to work with the following code:
struct flyweight_hash
{
std::size_t operator()(const boost::flyweight<std::string> &elm) const
{
boost::hash<std::string> hasher;
const std::string & str = elm.get();
return hasher(str);
}
};
and passed it as a template parameter to the construction of the map:
boost::unordered_map<boost::flyweight<std::string>, boost::flyweight<std::string> , flyweight_hash > map;
In this case I don´t understand way overloading hash_value didn´t worked.
boost::hash calls hash_value through argument dependent lookup (ADL). You are trying to define a hash_value function for a class in namespace boost. Hence your hash_value function would need to go into this namespace as well for ADL to work. Unfortunately, adding functions to a foreign namespace is rather evil and should be avoided. Your solution of using a custom hasher seems fine.
A little example code to illustrate:
namespace boost {
// somewhere in boost
template<typename T>
std::size_t hash(const T& t) {
// call using ADL
// e.g. if called with object of class type foo::bar this will
// pick up foo::hash_value despite the lack of namespace
// qualification
return hash_value(t);
}
}
// your hash_value (presumably in the global namespace)
// not picked up by above call
std::size_t hash_value(boost::flyweight<T>...);
namespace boost {
// this would be picked up but is slightly evil
std::size_t hash_value(boost::flyweight<T>...);
}
It is a pity to hash something which has already been hashed. Flyweight keeps a single instance of equal objects, so it is more efficient to hash the address of this instance, instead of its content. I do as follows (in std, not in boost, as I'm using C++11, so I'm extending std::hash, not boost::hash):
namespace std
{
template <typename T>
struct hash<boost::flyweight<T, boost::flyweights::no_tracking>>
{
using value_type = boost::flyweight<T, boost::flyweights::no_tracking>;
size_t operator()(const value_type& ss) const
{
hash<const void*> hasher;
return hasher(&ss.get());
}
};
}
I have been confirmed that this works by design, not by accident: http://lists.boost.org/boost-users/2013/03/78007.php

unordered_map hash function c++

I need to define an unordered_map like this unordered_map<pair<int, int>, *Foo>, what is the syntax for defining and passing a hash and equal functions to this map?
I've tried passing to it this object:
class pairHash{
public:
long operator()(const pair<int, int> &k) const{
return k.first * 100 + k.second;
}
};
and no luck:
unordered_map<pair<int, int>, int> map = unordered_map<pair<int, int>, int>(1,
*(new pairHash()));
I have no Idea what is the size_type_Buskets means so I gave it 1.
What is the right way to do it?
Thanks.
This is an unfortunate omission in C++11; Boost has the answer in terms of hash_combine. Feel free to just paste it from them! Here's how I hash pairs:
template <class T>
inline void hash_combine(std::size_t & seed, const T & v)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
namespace std
{
template<typename S, typename T> struct hash<pair<S, T>>
{
inline size_t operator()(const pair<S, T> & v) const
{
size_t seed = 0;
::hash_combine(seed, v.first);
::hash_combine(seed, v.second);
return seed;
}
};
}
You can use hash_combine as the basis for many other things, like tuples and ranges, so you could hash an entire (ordered) container, for example, as long as each member is individually hashable.
Now you can just declare a new map:
std::unordered_map<std::pair<int, int>, my_mapped_type> mymap;
If you want to use your homebrew hasher (which hasn't got good statistical properties), you have to specify the template parameters explicitly:
std::unordered_map<std::pair<int,int>, int, pairHash> yourmap;
Note that there's no need to specify a copy of a hasher object, as the default is to default-construct one for you.
The return type of the hash function should be size_t, not long (although this is not the cause of the error). The syntax you've shown for providing a custom hash function is incorrect.
You'll also need to provide an equal predicate to make the above work properly.
#include <unordered_map>
#include <utility>
using namespace std;
class pairHash{
public:
size_t operator()(const pair<int, int> &k) const{
return k.first * 100 + k.second;
}
};
struct pairEquals : binary_function<const pair<int,int>&, const pair<int,int>&, bool> {
result_type operator()( first_argument_type lhs, second_argument_type rhs ) const
{
return (lhs.first == rhs.first) && (lhs.second == rhs.second);
}
};
int main()
{
unordered_map<pair<int, int>, int, pairHash, pairEquals> myMap;
myMap[make_pair(10,20)] = 100;
myMap.insert( make_pair(make_pair(100,200), 1000) );
}
EDIT:
You don't need to define the equal predicate since operator== is defined for std::pair and it does exactly what I've done in pairEquals. You'll only need the pairEquals definition if you expect the comparison to be done differently.
If you are fine with using Boost, a cleaner solution is to rely on Boost's implementation of the hash function for pairs (which in fact does exactly what kerrek-sb explains in his answer). Therefore all you have to do is:
#include <unordered_map>
#include <boost/functional/hash.hpp>
using namespace std;
using namespace boost;
unordered_map<pair<int, int>, int, hash<pair<int, int>>> table;

iterator adapter to iterate just the values in a map?

I'm just getting back into C++ after a couple of years of doing a lot of C#, and recently Objective C.
One thing I've done before is to roll my own iterator adapter for std::map that will deref to just the value part, rather than the key-value pair. This is quite a common and natural thing to do. C# provides this facility with its Keys and Values properties of its Dictionary class. Objective-C's NSDictionary, similarly, has allKeys and allValues.
Since I've been "away", Boost has acquired the Range and ForEach libraries, which I am now using extensively. I wondered if between the two there was some facility to do the same, but I haven't been able to find anything.
I'm thinking of knocking something up using Boost's iterator adapters, but before I go down that route I thought I'd ask here if anyone knows of such a facility in Boost, or somewhere else ready made?
Replacing the previous answer, in case anybody else finds this like I did. As of boost 1.43, there are some commonly used range adaptors provided. In this case, you want boost::adaptors::map_values. The relevant example:
http://www.boost.org/doc/libs/1_46_0/libs/range/doc/html/range/reference/adaptors/reference/map_values.html#range.reference.adaptors.reference.map_values.map_values_example
I don't think there's anything out of the box. You can use boost::make_transform.
template<typename T1, typename T2> T2& take_second(const std::pair<T1, T2> &a_pair)
{
return a_pair.second;
}
void run_map_value()
{
map<int,string> a_map;
a_map[0] = "zero";
a_map[1] = "one";
a_map[2] = "two";
copy( boost::make_transform_iterator(a_map.begin(), take_second<int, string>),
boost::make_transform_iterator(a_map.end(), take_second<int, string>),
ostream_iterator<string>(cout, "\n")
);
}
There is a boost range adaptor for exactly this purpose.
See http://www.boost.org/doc/libs/1_53_0/libs/range/doc/html/range/reference/adaptors/reference/map_values.html
(This example cribbed from there)
int main(int argc, const char* argv[])
{
using namespace boost::assign;
using namespace boost::adaptors;
std::map<int,int> input;
for (int i = 0; i < 10; ++i)
input.insert(std::make_pair(i, i * 10));
boost::copy(
input | map_values,
std::ostream_iterator<int>(std::cout, ","));
return 0;
}
Continuing David's answer, there's another possibility to put the boile by creating a derived class from boost::transform_iterator. I'm using this solution in my projects:
namespace detail
{
template<bool IsConst, bool IsVolatile, typename T>
struct add_cv_if_c
{
typedef T type;
};
template<typename T>
struct add_cv_if_c<true, false, T>
{
typedef const T type;
};
template<typename T>
struct add_cv_if_c<false, true, T>
{
typedef volatile T type;
};
template<typename T>
struct add_cv_if_c<true, true, T>
{
typedef const volatile T type;
};
template<typename TestConst, typename TestVolatile, typename T>
struct add_cv_if: public add_cv_if_c<TestConst::value, TestVolatile::value, T>
{};
} // namespace detail
/** An unary function that accesses the member of class T specified in the MemberPtr template parameter.
The cv-qualification of T is preserved for MemberType
*/
template<typename T, typename MemberType, MemberType T::*MemberPtr>
struct access_member_f
{
// preserve cv-qualification of T for T::second_type
typedef typename detail::add_cv_if<
std::tr1::is_const<T>,
std::tr1::is_volatile<T>,
MemberType
>::type& result_type;
result_type operator ()(T& t) const
{
return t.*MemberPtr;
}
};
/** #short An iterator adaptor accessing the member called 'second' of the class the
iterator is pointing to.
*/
template<typename Iterator>
class accessing_second_iterator: public
boost::transform_iterator<
access_member_f<
// note: we use the Iterator's reference because this type
// is the cv-qualified iterated type (as opposed to value_type).
// We want to preserve the cv-qualification because the iterator
// might be a const_iterator e.g. iterating a const
// std::pair<> but std::pair<>::second_type isn't automatically
// const just because the pair is const - access_member_f is
// preserving the cv-qualification, otherwise compiler errors will
// be the result
typename std::tr1::remove_reference<
typename std::iterator_traits<Iterator>::reference
>::type,
typename std::iterator_traits<Iterator>::value_type::second_type,
&std::iterator_traits<Iterator>::value_type::second
>,
Iterator
>
{
typedef boost::transform_iterator<
access_member_f<
typename std::tr1::remove_reference<
typename std::iterator_traits<Iterator>::reference
>::type,
typename std::iterator_traits<Iterator>::value_type::second_type,
&std::iterator_traits<Iterator>::value_type::second
>,
Iterator
> baseclass;
public:
accessing_second_iterator():
baseclass()
{}
// note: allow implicit conversion from Iterator
accessing_second_iterator(Iterator it):
baseclass(it)
{}
};
This leads to even cleaner code:
void run_map_value()
{
typedef map<int, string> a_map_t;
a_map_t a_map;
a_map[0] = "zero";
a_map[1] = "one";
a_map[2] = "two";
typedef accessing_second_iterator<a_map_t::const_iterator> ia_t;
// note: specify the iterator adaptor type explicitly as template type, enabling
// implicit conversion from begin()/end()
copy<ia_t>(a_map.begin(), a_map.end(),
ostream_iterator<string>(cout, "\n")
);
}