I'am trying to use std::unordered_set in cross-platform C++ application. It compiles and works like a charm in Visual C++ under Windows, but generates a fatal compilation error on clang under Mac OS X.
I want to know why it happens and what is the right way to get this working.
Example code:
//
// Clang build cmdline:
// $ clang++ ./set.cpp -Wall -Werror -Wfatal-errors -std=c++11 -stdlib=libc++ -o set.out
//
#include <iostream>
#include <unordered_set>
struct Point {
int x, y;
Point(int x = 0, int y = 0) {
this->x = x;
this->y = y;
}
bool operator==(Point const& p) const {
return this->x == p.x && this->y == p.y;
}
operator std::size_t () const {
return std::hash<int>()(x) ^ std::hash<int>()(y);
}
};
typedef std::unordered_set<Point> points_set_t;
int main() {
Point point1(1, 5);
Point point2(1, 1);
Point point3(1, 5);
points_set_t points;
points.insert(point1);
points.insert(point2);
points.insert(point3);
for (points_set_t::const_iterator it = points.begin(); it != points.end(); it++) {
std::cout << it->x << ":" << it->y << std::endl;
}
}
Clang output:
In file included from ./set.cpp:6:
In file included from /usr/bin/../lib/c++/v1/iostream:38:
In file included from /usr/bin/../lib/c++/v1/ios:216:
In file included from /usr/bin/../lib/c++/v1/__locale:15:
In file included from /usr/bin/../lib/c++/v1/string:434:
In file included from /usr/bin/../lib/c++/v1/algorithm:591:
/usr/bin/../lib/c++/v1/type_traits:748:38: fatal error: implicit instantiation of undefined template 'std::__1::hash<Point>'
: public integral_constant<bool, __is_empty(_Tp)> {};
^
/usr/bin/../lib/c++/v1/memory:1948:40: note: in instantiation of template class 'std::__1::is_empty<std::__1::hash<Point> >'
requested here
bool = is_empty<_T2>::value
^
/usr/bin/../lib/c++/v1/memory:1970:44: note: in instantiation of default argument for '__libcpp_compressed_pair_switch<unsigned
long, std::__1::hash<Point>, false, false>' required here
template <class _T1, class _T2, unsigned = __libcpp_compressed_pair_switch<_T1, _T2>::value>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/c++/v1/memory:2354:15: note: in instantiation of default argument for '__libcpp_compressed_pair_imp<unsigned long,
std::__1::hash<Point> >' required here
: private __libcpp_compressed_pair_imp<_T1, _T2>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/c++/v1/__hash_table:527:55: note: in instantiation of template class 'std::__1::__compressed_pair<unsigned long,
std::__1::hash<Point> >' requested here
__compressed_pair<size_type, hasher> __p2_;
^
/usr/bin/../lib/c++/v1/unordered_set:330:13: note: in instantiation of template class 'std::__1::__hash_table<Point,
std::__1::hash<Point>, std::__1::equal_to<Point>, std::__1::allocator<Point> >' requested here
__table __table_;
^
./set.cpp:28:18: note: in instantiation of template class 'std::__1::unordered_set<Point, std::__1::hash<Point>,
std::__1::equal_to<Point>, std::__1::allocator<Point> >' requested here
points_set_t points;
^
/usr/bin/../lib/c++/v1/memory:3076:29: note: template is declared here
template <class _Tp> struct hash;
^
1 error generated.
UPD Working implementation using @mfontanini's suggestion: https://gist.github.com/vbo/6090142.
unordered_set time was better than set (15494846) : 93<155. Only with adding this line: s.
The Unordered_set allows only unique keys, for duplicate keys unordered_multiset should be used. Example of declaration, find, insert and iteration in unordered_set is given below : CPP.
Unordered sets do not allow duplicates and are initialized using comma-delimited values enclosed in curly braces.
They are implemented as a hash table in memory. The element in the unordered_set acts as both key and value in the hash table. All operations take O(1) time on average and O(N) time in the worst case. Unordered_set is present in #include<unordered_set> header file.
In order to make std::unordered_set
work with your Point
class, you can provide a std::hash
specialization for it:
namespace std
{
template<>
struct hash<Point> {
size_t operator()(const Point &pt) const {
return std::hash<int>()(pt.x) ^ std::hash<int>()(pt.y);
}
};
}
You could also change std::unordered_set
's second template parameter(it defaults to std::hash<Point>
), which indicates a functor type that returns the required hash.
It seems like you tried providing this hash implementation via a user defined conversion to size_t
, but that won't work. The fact that it works in VC is caused by some bug in their implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With