将 std::set 与基于键的比较器一起使用

Using std::set with a key-based comparator

本文关键字:比较器 一起 std set 于键      更新时间:2023-10-16

>假设我有一组(或映射(字符串,我想使用仅比较前 5 个字符的自定义比较器。所以"abcde"和"abcdef"在我的集合中是一样的。

typedef std::set<std::string, Cmp> MySet;

编写 CMP 的最佳方法是什么?

显而易见的方式是这样的:

struct Cmp
{
bool operator()(const string& x, const string& y)
{
return (x.substr(0, 5) < y.substr(0, 5));
}
}

问题是此代码重复.substr(0, 5).在此示例中,它很短,但在一般情况下,它可能会更长。我想避免这种重复的代码。

一般来说,给定T1, T2类型和函数T2 key(T1& const),我想要一组根据key(a) < key(b)进行比较的T1元素,其中对T2的比较已经明确定义。写这个最好的方法是什么?我想过写一个新的class KeyBaseSet,但那会为我的单一用例过度设计。有没有办法使用std或 Boost 来做到这一点?

我正在寻找类似于在 Python (https://docs.python.org/3/howto/sorting.html#key-functions( 中排序时的key参数或 Haskell (https://stackoverflow.com/a/2788262/351105( 中的compare `on`习语。

您可以使用密钥策略自定义Cmp。最小示例:

template<class Key>
struct Compare_on {
Compare_on(Key key = Key()) : key_(key)
{}
template<class T>
bool operator()(const T& x, const T& y) const {
return key_(x) < key_(y);
}
private:
Key key_;
};
struct First3 {
std::string_view operator()(const std::string& s) const {
return std::string_view(s).substr(0, 3);
}
};
// Example:
std::set<std::string, Compare_on<First3>> set;
set.insert("abc1");
set.insert("abc2");

演示

<小时 />Compare_on

可以通过使其成为透明比较器来改善:

template<class Key>
struct Compare_on {
using is_transparent = void;
Compare_on(Key key = Key()) : key_(key)
{}
template<class T1, class T2>
bool operator()(const T1& x, const T2& y) const {
return key_(x) < key_(y);
}
private:
Key key_;
};
struct First3 {
template<class T>
std::string_view operator()(const T& s) const {
return std::string_view(s).substr(0, 3);
}
};

现在当我们这样做时

auto pos = set.find("abc");

不会为字符串文本"abc"构造临时std::string

演示 2

你的问题可以用高阶函数来解决。本质上是一个函数,它采用T2 key(const T1&)函数并返回一个可用作std::set比较器的新函数。像这样:

auto make_comp(T key) {
return [key](const auto& v1, const auto& v2){return key(v1) < key(v2);};
}

显然,此示例需要通用 lambda,但也应该可以使用模板结构来实现这一点:)

应该可以将集合定义为std::set<decltype(make_comp([](){...}))>