2012-01-01 40 views
10

Tôi cố gắng để làm như sau:Làm thế nào để làm tăng unordered_map để hỗ trợ hạng ruồi <string>

boost::unordered_map<boost::flyweight<std::string>, boost::flyweight<std::string> > map; 

     boost::flyweight<std::string> foo(name); 
     map[foo] = foo; 

Nhưng trình biên dịch phàn nàn: "lỗi C2665: 'đẩy mạnh :: hash_value': không ai trong số 17 quá tải có thể chuyển đổi tất cả các loại đối số ".

Nhưng tôi đã xác định các chức năng sau:

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(); 
} 

Nhưng nó doesn't biên dịch.

Tôi cần làm gì để tăng unordered_map để hỗ trợ trọng tải?

[EDIT] tôi đã nhận nó để làm việc với đoạn mã sau:

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

và thông qua nó như một tham số mẫu để xây dựng các bản đồ:

boost::unordered_map<boost::flyweight<std::string>, boost::flyweight<std::string> , flyweight_hash > map; 

Trong trường hợp này tôi không hiểu cách quá tải hash_value đã không làm việc.

Trả lời

7

boost::hash gọi hash_value thông qua tra cứu phụ thuộc đối số (ADL). Bạn đang cố gắng xác định hàm hash_value cho một lớp trong không gian tên boost. Do đó, hàm hash_value của bạn sẽ cần phải đi vào không gian tên này để ADL hoạt động. Thật không may, việc thêm các hàm vào một không gian tên nước ngoài khá là xấu và cần tránh. Giải pháp của bạn bằng cách sử dụng một hasher tùy chỉnh có vẻ tốt.

Một chút mã ví dụ để minh họa:

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>...); 
} 
+0

Nó chỉ xấu vì hasher mặc định của 'boost :: unordered_map' dường như không kích hoạt ADL bằng' using boost :: hash_value; return hash_value (khóa); Tôi không thể kiểm tra ngay bây giờ. – Xeo

+0

@Xeo Mặc định hasher nên là 'boost :: hash' và không nên cụ thể cho' unordered_map'. Ít nhất là doc nói vậy. – pmr

+0

Chắc chắn, nhưng điều đó không thay đổi các cuộc gọi hỗ trợ ADL dường như không được sử dụng. – Xeo

5

Đó là một điều đáng tiếc để băm cái gì đó đã được băm. Flyweight giữ một thể hiện đơn lẻ của các đối tượng bằng nhau, do đó, nó là hiệu quả hơn để băm địa chỉ của trường hợp này, thay vì nội dung của nó. Tôi làm như sau (trong std, không phải trong boost, như tôi đang sử dụng C++ 11, vì vậy tôi mở rộng std::hash, không 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()); 
    } 
    }; 
} 

Tôi đã được xác nhận rằng đây hoạt động bằng cách thiết kế, không phải ngẫu nhiên: http://lists.boost.org/boost-users/2013/03/78007.php

Các vấn đề liên quan