C++定义自定义unordered_set的不同方法

C++ what's different ways to define customized unordered_set

本文关键字:方法 set 定义 自定义 unordered C++      更新时间:2023-10-16

作为一个C++学习者,我认为这是一个语法层面的问题C++。

我找到了三种方法来定义自定义unordered_set,但我不太清楚该语法是什么意思......

struct myclass {
int data;
};
size_t hashfun(const myclass &m) { return std::hash<int>()(m.data); };
bool eqfun(const myclass &m1, const myclass &m2) { return m1.data == m2.data; };
struct myhash {
size_t operator()(const myclass &m) {
return std::hash<int>()(m.data);
}
};
int main() {
auto hash_lambda = [](const myclass &m) { return std::hash<int>()(m.data); };
auto eq_lambda = [](const myclass &m1, const myclass &m2) { return m1.data == m2.data; };

std::unordered_set<myclass, decltype(hash_lambda), decltype(eq_lambda)> set1(42, hash_lambda, eq_lambda);

std::unordered_set<myclass, decltype(hashfun) *, decltype(eqfun) *> set2(42, hash_lambda,eq_lambda);    
std::unordered_set<myclass, myhash> set3;

}

因此,方法1:提供一个哈希函数和一个相等的功能; 方法 2:与方法 1 非常相似,但使用 lambda; 方法 3:提供带有重载运算符 (( 的结构。

这是我的问题:

  1. 为什么使用正常功能时decltype带有*,而与 lambda 一起使用时没有*

  2. 当使用方法 1/2 时,为什么我们需要在初始化 unordered_set 对象时提供函数实例,而 Approach 则不需要?

  3. 如果有的话,3 种方法中的现代C++"最佳实践"是什么?

为什么在与正常函数一起使用时用 * 去 decltype,而在 lambda 中使用时没有 *?

因为 lambda 的类型是一个未命名的类。该语言定义了与myhash基本相同的内容。函数不是对象,但函数指针是对象。

使用方法1/2时,为什么我们需要提供函数 在接近时初始化unordered_set对象时的实例 3 没有?

因为myhash可以默认构造。函数指针的值初始化为空指针,并且 lambda 类型具有已删除的默认构造函数。

如果有的话,3 种方法中的现代C++"最佳实践"是什么?

我建议使用类的"自然"哈希,没有这些。相反,我会专门研究std::hash<myclass>,并提供operator ==。您可以为用户定义的类型添加专用namespace std模板。

// In the same namespace as myclass
bool operator==(const myclass & lhs, const myclass & rhs)
{ return lhs.data == rhs.data; }
namespace std {
template <> struct hash<myclass>
{
size_t operator()(const myclass & x) const
{
return std::hash<int>()(m.data);
}
};
}

这允许您使用std::unordered_set<myclass>,将所有其他参数保留为默认值。

lambda 和函数指针之间区别的原因是因为

decltype(hashfun)

返回函数的类型,而不是函数指针。要获取函数指针的类型,您需要在末尾添加星号或在decltype中获取函数的地址:

decltype(&hashfun)

令人困惑的是,c++ 允许您在将函数分配给函数指针时省略&,这两行是等效且合法的:

decltype(&hashfun) f = &hashfun;
decltype(&hashfun) g = hashfun;

但是这些不会编译(你不能用函数的类型声明变量(:

decltype(hashfun) f = &hashfun;
decltype(hashfun) g = hashfun;

您使用 3 种方法中的哪一种完全取决于您,lambda 可能会产生最快的代码,因为编译器可以完全内联它们,但性能差异可能并不显着。

编写最容易理解的代码,并在以后发现确实需要时对其进行优化。