在Visual C++和clang中使用C++ 11 unordered_set

vbo*_*vbo 9 c++ clang unordered-set visual-c++ c++11

我试图在跨平台的C++应用程序中使用std :: unordered_set.它在Windows下编译和工作就像Visual C++中的魅力,但在Mac OS X下的clang上产生致命的编译错误.

我想知道它为什么会发生,以及正确的方法是什么.

示例代码:

// 
// 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

Clang输出:

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.      
Run Code Online (Sandbox Code Playgroud)

UPD使用@ mfontanini建议的工作实现:https://gist.github.com/vbo/6090142 .

mfo*_*ini 17

为了std::unordered_set与您的Point班级合作,您可以为其提供std::hash专业化:

namespace std
{
template<>
struct hash<Point> {
    size_t operator()(const Point &pt) const {
        return std::hash<int>()(pt.x) ^ std::hash<int>()(pt.y);
    }
};
}
Run Code Online (Sandbox Code Playgroud)

您还可以更改std::unordered_set第二个模板参数(默认为std::hash<Point>),这表示返回所需哈希的仿函数类型.

您似乎尝试通过用户定义的转换提供此哈希实现size_t,但这不起作用.它在VC中工作的事实是由它们的实现中的一些错误引起的.

  • @vbo:因为Visual Studio显然正在做一些它不应该做的事情.(最有可能的是,定义主要`hash`模板的无用实现,或者可能使用转换运算符,但这只是猜测). (2认同)