带有覆盖运算符或外部函子的可哈希类型

问题描述 投票:2回答:1

要在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定义两个不同的比较器),哪种方法更可取?两者之间还有什么其他区别?

c++ templates functor unordered-set
1个回答
1
投票

将行为附加到类型允许使用类似代码

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_setstd::find的默认值;如果您希望达到这些目的的等效性有所不同,则可能需要命名比较器。另一方面,如果足够的话,C ++ 20甚至可以只用=default来定义它。

© www.soinside.com 2019 - 2024. All rights reserved.