Không thể một phần chức năng chuyên biệt mẫu, và như vậy cho người dùng định nghĩa các lớp templated, sẽ không có cách nào để chuyên std::hash
nếu nó là một chức năng. (bạn chỉ có thể chuyên mẫu từ không gian tên std
, nhưng không quá tải, vì vậy người dùng của lớp templated của bạn không thể tạo std::unordered_map<MyClass<whatever>, MyOtherClass>
, họ sẽ bị buộc phải chọn std::unordered_map<MyClass<whatever>, MyOtherClass, ???>
). Vì vậy, functor là giải pháp ở đây.
namespace std
{
template<typename T>
struct hash<MyVector<T>>
{
size_t operator()(const MyVector<T>& v)
{
//return hash from here
}
};
}
Cách thay thế cho thư viện tiêu chuẩn sẽ được sử dụng một số SFINAE mẫu lừa để lựa chọn thành viên .hash()
như là mặc định, và băm tiêu chuẩn nếu các trường hợp khác, nhưng trong hầu hết các trường hợp, bạn không thể trang bị thêm giao diện (đặc biệt nếu sử dụng mã bên thứ ba)
Các thay thế khác sẽ như thế nào std::swap
không (thủ đoạn với ADL):
//somewhere in std::unordered_map
using std::hash;
size_t h = hash(key);
Theo kinh nghiệm của tôi, ADL là khó khăn và không phải ai cũng nhớ về trường hợp góc. Hơn nữa, lợi thế của các functors ở đây là bạn có thể sử dụng chúng như một tham số mẫu, vì vậy bạn có thể chỉ cần cắm thêm một functor cho mẫu (như std::unordered_map<A, B, specialized_hash<A>>
) nếu bạn nghĩ rằng mặc định là không phù hợp với trường hợp của bạn.
Từ nhận xét:
Nhưng bạn có thể xây dựng thêm một chút về std :: hoán đổi? Nó vẫn còn có trong C++ 11 và nó không có vấn đề với các loại do người dùng định nghĩa, phải không? Tại sao giữ nhiều khái niệm khác nhau trong STL thay vì làm cho nó nhiều hơn nhất quán?
Có một sự khác biệt nhỏ giữa std::swap
và std::hash
:
Trong std::hash
:
- nó có khả năng đó, ví dụ
std::string
băm được xác định bởi tác giả của lớp sẽ không đủ cho trường hợp của bạn, nghĩa là nó quá chung chung và bạn có thể đảm bảo trong bản đồ băm của mình rằng bạn sẽ đặt chuỗi chỉ một loại, vì vậy bạn có thể cung cấp hàm băm nhanh hơn hoặc và có ít va chạm hơn.
- có rất nhiều loại băm cho các mục đích khác nhau nên genericity là ít quan trọng ở đây
- trong nhiều trường hợp nó có thể cho bạn để tạo một hash tốt hơn
Trong std::swap
:
- nó không chắc rằng bạn sẽ muốn có chức năng hoán đổi của riêng bạn, nhưng bạn vẫn có thể muốn sử dụng một hàm cụ thể cho lớp này, chứ không phải là một hàm gọi chung
std::swap
gọi các hàm tạo bản sao.
- trong hầu hết các trường hợp, bạn không thể tạo chức năng hoán đổi, vì nó đòi hỏi kiến thức về nội dung lớp (ví dụ:
std::vector
có thể được thực hiện dưới dạng mảng động với con trỏ ẩn dưới dạng trường riêng tư, vì vậy bạn sẽ không có thể truy cập chúng, không phải một mình hoán đổi chúng, và thậm chí thực tế được thực hiện theo cách đó không được đảm bảo)
- có (hoặc phải) chỉ có một lần hoán đổi.
- thực tế, có sự cố với
std::swap
: các thùng chứa chuẩn cung cấp chức năng swap
, std::swap
có thể chuyên biệt (nhưng chỉ dành cho lớp không có templated) và trao đổi có thể được định nghĩa là chức năng miễn phí được tìm thấy với ADL. Làm thế nào bạn nên cung cấp trao đổi của riêng bạn? IMO gây nhầm lẫn, không thực tế là std::swap
là hàm và std::hash
là một hàm.
Tại sao STL không nhất quán? Tôi chỉ có thể đoán ở đây, nhưng lý do chính tại sao STL không nhất quán là (a) khả năng tương thích bawkward và (b) C++ cũng khá không nhất quán.
@RiaD Đúng, cảm ơn. Đột nhiên, nó cảm thấy khó xử hơn. –