在下面的代码中,
values
向量包含由indexes
索引的数据。它对于排序或搜索效果很好,而我必须一次处理比较器中的一个值(实际上是一对)。当我想在对索引进行排序时使用数组元素序列时,问题就出现了;它们必须不是按值排序,而是按值序列排序。
问题(我想要实现的目标)
std::ranges::equal_range
中比较的值(见下文),以便我可以将其保留在std::ranges::equal_range
调用的适当位置?肮脏且危险的解决方法
ChainComparator
来实现这个技巧,它捕获向量并使用其中的信息,这适用于排序,但不适用于 std::ranges::equal_range
,因为要比较的值不属于值向量。请参阅下面的代码。 (演示)。ChainComparator
的第二个参数传递,并使用“特殊值”(如 -1),如果我在比较器中看到它,则从此参数中获取比较值。但这确实是肮脏的黑客行为,在我的例子中我不能有像 -1 这样的特殊值。 (如果需要的话我可以做一个演示)。我想避免什么
ChainComparator
,因为如果开发人员提供错误的向量,它很容易出错。当然,这可以在比较器中检查,但仅在执行时间中检查,并且成本高昂。ChainComparator
参数传递,因为这会使比较器不那么通用,并且会违反“单一任务”规则。最好保留原来的搜索语法。此外,我有很多比较器,当参数化谓词通过我的函数层次结构时,向每个比较器引入这样的支持成本高昂且容易出错。代码
auto make_index_projection = []<std::ranges::random_access_range R>(R & range) {
return [&range](std::ranges::range_difference_t<R> i) -> decltype(auto) {
return std::ranges::begin(range)[i];
};
};
class ChainComparator {
const std::vector<int>& vec;
public:
ChainComparator(const auto& vec) : vec(vec) {}
bool operator() (int& lhs, int& rhs) {
auto lhs_range_begin = vec.begin() + (&lhs - std::data(vec));
auto rhs_range_begin = vec.begin() + (&rhs - std::data(vec));
return std::lexicographical_compare(lhs_range_begin, vec.end(), rhs_range_begin, vec.end());
}
};
int main()
{
std::vector<int> values = { 0,30,20,40,10 };
std::vector<int> indexes = { 3,4,2,1,0 };
auto index_projection = make_index_projection(values);
std::ranges::sort(indexes, ChainComparator(values), index_projection);
auto indexing_view = indexes | std::views::transform(index_projection);
int value_to_search = 30;
// Error with value here
auto range_pred = std::ranges::equal_range(indexing_view, value_to_search, ChainComparator(values));
std::vector<int> values_to_search = { 20, 40 };
// Error with value here
auto range_pred_seq = std::ranges::equal_range(indexing_view, values_to_search, ChainComparator(values));
}
当然这是可行的。毕竟,范围确实非常强大且灵活:)
make_index_projection
现在返回范围中的单个左值,但您也可以返回子范围,这是从指定元素到您感兴趣的任何位置的视图。在您的示例代码中,您似乎感兴趣的是从给定元素到末尾的子范围,所以让我们也这样做。为了更好的演示,我使用 std::string
(一系列 char
,而不是一系列 int
),因为打印 string
更容易。
演示:https://godbolt.org/z/oWa6n47j1
我将编辑答案以添加更多详细信息,但上面的演示已包含所有信息。