作为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:除了使用lambda之外,其他方法与方法1非常相似;方法3:为结构提供重载operator()。
这是我的问题:
为什么将decltype
与*
一起使用,但使用普通函数却没有*
与lambda一起使用?
在使用方法1/2时,为什么在不使用方法1/2初始化unordered_set对象时需要提供函数实例?
在3种方法中,有什么现代的C ++“最佳实践”?
答案 0 :(得分:1)
为什么在正常功能下使用带*的十进制类型,而在lambda上却没有*?
因为lambda的类型是未命名的类。该语言定义的内容与myhash
基本相同。函数不是对象,而函数指针是。
使用方法1/2时,为什么需要提供功能 实例时初始化unordered_set对象时的实例 3不?
因为myhash
是默认构造的。函数指针会将值初始化为空指针,并且lambda类型具有已删除的默认构造函数。
如果有的话,什么是3种现代C ++“最佳实践”?
对于类的“自然”散列,我建议不要使用。相反,我将专门研究std::hash<myclass>
,并提供一个operator ==
。您是permitted的用户,他们在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>
,而将所有其他参数保留为默认值。
答案 1 :(得分:0)
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可能会导致最快的代码,因为编译器可以完全内联它们,但是性能差异可能并不明显。
写出最容易理解的代码,并在以后发现确实需要时对其进行优化。