C++定义自定义unordered_set的不同方法
C++ what's different ways to define customized unordered_set
作为一个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:提供带有重载运算符 (( 的结构。
这是我的问题:
为什么使用正常功能时
decltype
带有*
,而与 lambda 一起使用时没有*
?当使用方法 1/2 时,为什么我们需要在初始化 unordered_set 对象时提供函数实例,而 Approach 则不需要?
如果有的话,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 可能会产生最快的代码,因为编译器可以完全内联它们,但性能差异可能并不显着。
编写最容易理解的代码,并在以后发现确实需要时对其进行优化。
- 将 std:set<int32_t> 复制到 std::set <uint32_t>的好方法
- 使用Set/Get-like方法或GetSet组合函数
- 在std :: Map或std :: set中找到具有给定前缀的键的优雅方法
- 返回get/set方法中的向量
- 如何实例化多个 set 对象来测试 Set 类的各种构造函数和方法
- 删除 std::set<Node *> 中的元素的正确方法
- 为什么 c++ 中没有重复的 protobuf 字段的 Set 方法
- 公共全局变量或get()和set()方法
- 在C++中编写简单的 get/set 方法时,是否应始终使用 const 引用作为参数
- C++通过ref返回成员的方法和get-set方法之间的差异
- 将 set 方法与指针/类一起使用
- C++类和对象使用set方法获得用户输入
- 封装设计气味与get/set方法
- 在std::set/std::map中存储具有多个不同类型字段的c++对象的有效方法
- 如何返回“set”方法的子类类型
- 如何在c++中使用get和set方法来初始化一个用new初始化的对象?
- 为什么C++ STL set 容器的 count() 方法被命名为这样?
- c++ set/get方法同步
- 获取std::set子集的有效方法
- 传递NULL与分配空std::set传递给方法的可行性和性能