具有覆盖运算符或外部仿函数的可散列类型
Hashable type with overwritten operators or external functors
要在 std::unordered_set
中使用自定义类型,我必须选择。
1) 为我的类型实现 ==
运算符并特化 std::hash
struct MyType {
int x;
bool operator==(const MyType& o) {
return this.x == o.x;
}
};
namespace std
{
template<>
struct hash<MyType> {
size_t operator()(const MyType& o) const {
return hash<int>()(o.x);
}
};
}
std::unordered_set<MyType> mySet;
或2),提供函子类:
struct MyTypeHash {
size_t operator()(const MyType& o) const {
return std::hash<int>()(o.x);
}
};
struct MyTypeCompare {
bool operator()(const MyType& o1, const MyType& o2) const {
return o1.x == o2.x;
}
};
std::unordered_set<MyType, MyTypeHash, MyTypeCompare> mySet;
第二种方法让我为 std::unordered_set
的每个新实例选择新的行为,而第一种方法作为类型本身的一部分的行为将始终相同。
现在,如果我知道我只想要一个行为(我永远不会为 MyType
定义两个不同的比较器),那么首选哪种方法?这两者之间还有哪些其他区别?
将行为附加到类型允许像
这样的代码
template<template<class> Set,class T>
auto organizeWithSet(…);
/* elsewhere */ {
organizeWithSet<std::unordered_set,MyType>(…);
organizeWithSet<std::set,MyType>(…);
}
显然不能传递自定义函数对象
也就是说,可以定义
template<class T>
using MyUnorderedSet=std::unordered_set<T, MyTypeHash,MyTypeCompare>;
并将其用作模板模板参数,尽管这引入了另一个名称并且可能被认为可读性较差。
否则,您必须考虑到您的 operator==
同时是 std::unordered_set
和 std::find
等的默认设置;如果出于这些目的您想要的等价物有所不同,您可能需要命名比较器。另一方面,如果一个就足够了,C++20 甚至可以让您仅用 =default
.
来定义它
要在 std::unordered_set
中使用自定义类型,我必须选择。
1) 为我的类型实现 ==
运算符并特化 std::hash
struct MyType {
int x;
bool operator==(const MyType& o) {
return this.x == o.x;
}
};
namespace std
{
template<>
struct hash<MyType> {
size_t operator()(const MyType& o) const {
return hash<int>()(o.x);
}
};
}
std::unordered_set<MyType> mySet;
或2),提供函子类:
struct MyTypeHash {
size_t operator()(const MyType& o) const {
return std::hash<int>()(o.x);
}
};
struct MyTypeCompare {
bool operator()(const MyType& o1, const MyType& o2) const {
return o1.x == o2.x;
}
};
std::unordered_set<MyType, MyTypeHash, MyTypeCompare> mySet;
第二种方法让我为 std::unordered_set
的每个新实例选择新的行为,而第一种方法作为类型本身的一部分的行为将始终相同。
现在,如果我知道我只想要一个行为(我永远不会为 MyType
定义两个不同的比较器),那么首选哪种方法?这两者之间还有哪些其他区别?
将行为附加到类型允许像
这样的代码template<template<class> Set,class T>
auto organizeWithSet(…);
/* elsewhere */ {
organizeWithSet<std::unordered_set,MyType>(…);
organizeWithSet<std::set,MyType>(…);
}
显然不能传递自定义函数对象
也就是说,可以定义
template<class T>
using MyUnorderedSet=std::unordered_set<T, MyTypeHash,MyTypeCompare>;
并将其用作模板模板参数,尽管这引入了另一个名称并且可能被认为可读性较差。
否则,您必须考虑到您的 operator==
同时是 std::unordered_set
和 std::find
等的默认设置;如果出于这些目的您想要的等价物有所不同,您可能需要命名比较器。另一方面,如果一个就足够了,C++20 甚至可以让您仅用 =default
.