C ++定义自定义unordered_set的不同方法是什么

时间:2018-09-14 05:38:03

标签: c++ c++11

作为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()。

这是我的问题:

  1. 为什么将decltype*一起使用,但使用普通函数却没有*与lambda一起使用?

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

  3. 在3种方法中,有什么现代的C ++“最佳实践”?

2 个答案:

答案 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可能会导致最快的代码,因为编译器可以完全内联它们,但是性能差异可能并不明显。

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