2013-07-26 3 views
9

크로스 플랫폼 C++ 응용 프로그램에서 std :: unordered_set을 사용하려고합니다. Windows에서 Visual C++의 매력처럼 작동하지만 Mac OS X에서 clang에 치명적인 컴파일 오류가 발생합니다.Visual C++에서 unordered_set을 사용하는 경우

왜 이런 일이 발생하는지 그리고이 작업을 수행하는 올바른 방법은 무엇인지 알고 싶습니다.

예 번호 :

// 
// 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; 
    } 
} 

연타 출력 :

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 @ mfontanini의 제안에 사용 작업 구현 : https://gist.github.com/vbo/6090142한다.

+0

해시 함수/펑터를 제공해야합니다. – juanchopanza

답변

17

Point 클래스와 std::unordered_set 작업을하기 위해서는, 당신은 그것을 위해 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); 
    } 
}; 
} 

당신은 또한 (std::hash<Point>에 기본값) std::unordered_set의 두 번째 템플릿 매개 변수를 변경할 수있는 나타냅니다 필요한 해시를 반환하는 Functor 유형

size_t으로 사용자 정의 변환을 통해이 해시 구현을 시도했지만 작동하지 않는 것 같습니다. VC에서 작동한다는 사실은 구현상의 버그로 인해 발생합니다.

+0

@juanchopanza 맞아, 그 중 하나 놓 쳤어. 감사. – mfontanini

+0

좋아, 좋아 보인다. 하지만 Visual Studio에서 왜 작동합니까? – vbo

+0

@vbo 분명히, VC의 구현 도청, 사용자 정의 변환 작업을 만들고있어. – mfontanini