【问题标题】:How to to pass iterators to the std::lower_bound() comparison function?如何将迭代器传递给 std::lower_bound() 比较函数?
【发布时间】:2018-02-14 15:48:31
【问题描述】:

以下声明借自cplusplus.com

template<class ForwardIterator, class T, class Compare>
ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& val, Compare comp);

comp() 应该类似于这样:

template<class T>
bool comp(const T& v1, const T& v2);

问题是我不想在那里传递值类型。我想将迭代器传递给它,然后 shift 它们 好的,在取消引用之前,只需在 comp() 内默默地盯着它们。 (更不用说 - 记录它们。)有什么解决方法吗?

当然,我可以用自己的迭代器编写自己的容器类,当然也可以编写自己的std::lower_bound() 实现。这两种选择都相当不愉快。

【问题讨论】:

  • 练习的最终目标是什么?你在comp 中说你想做的事情对我来说没有多大意义。听起来像XY problem
  • 嗯,这有点用处。我会检查 Boost,否则是的,请自行选择。
  • @YSC "你的迭代器是 ContiguousIterator 吗?" - 现在,他们是。我已准备好将std::vector 用作此处的容器。有什么帮助吗?

标签: c++ std stl-algorithm


【解决方案1】:

std::lower_bound doc,可以读到bool comp(const Type1 &amp;a, const Type2 &amp;b);

Type1 类型必须使得ForwardIt 类型的对象可以被取消引用,然后隐式转换为Type1Type2 类型必须使得T 类型的对象可以隐式转换为Type2。​

这意味着,std::lower_bound 将始终使用范围中的元素作为左侧参数调用 comp,并将 value 作为右侧参数。如果您的搜索范围是一个连续的范围(意味着您正在处理 std::vectorstd::arraystd::valarraystd::string、... 或 C 样式的数组),您可以从远处设计一个迭代器在范围的开始和comp 的左侧参数之间:

auto v = std::vector<int>{0, 1, 2, 3, 4, 5};

auto comp = [&v](const int &lhs, const int &rhs)
{
    auto it_lhs = cbegin(v) + std::distance(std::addressof(*cbegin(v)), &lhs);
    return *it_lhs < rhs;
};

std::cout << *std::lower_bound(begin(v), end(v), 2, comp) << "\n";

【讨论】:

  • 伙计,很明显lower_bound() 不会直接接受迭代器——就像在它的原型中一样。我要的是一种解决方法。也许还有另一个功能可以满足我的需求。或者也许有一个像 Mateusz Grzejek 建议的技巧。同时尝试那个。
  • @sigil 你不能从value 设计一个迭代器; see for yourself。这是UB。像 SIGSEGV UB。只有保证value 始终是comp 的右侧参数,它才会起作用。但我不建议考虑这个实现细节。
  • @sigil 我的错,它保证的。已更新。
【解决方案2】:

来自the doc

谓词函数的签名应该等价于 以下:

bool pred(const Type1 &amp;a, const Type2 &amp;b);

签名不需要有const &amp;,但函数一定不能 修改传递给它的对象。

所以你不能也不应该这样做。 std::lower_bound 有特定用途,不应以任何方式修改输入。为此目的编写您自己的函数。


如果您只需要索引,并且您的容器将其元素存储在线性、连续的内存块中,您可以这样做(以std::vector 为例):

std::vector<...> vec;
...
const auto* firstElemPtr = &vec[0];
std::lower_bound(vec.begin(), vec.end(), key, [firstElemPtr](const auto& left, const auto& right) -> bool {
  size_t index = &left - firstElemPtr;
  // now do the comparison
});

【讨论】:

  • 我不会修改任何输入。郑重承诺。假设容器是一个向量,我只想记录索引以进行调试。
  • 当 OP 写他们想要“移位迭代器”时,我不确定他们是否想要在这里实际移位值。
  • @sigil 如果都是关于索引,可以在特定条件下完成,请参阅更新。
  • 我想了想并用这个想法写了一个答案,但我担心comp必须在某个时候以key作为参数调用。获取key 的地址并将其视为数组是未定义的行为。
  • @YSC “当 OP 写他们想要“移动迭代器”时,我不确定他们是否想要在这里实际移位值。 - 没有一点偏移。说实话,它是一个经过旋转的排序向量。 {4, 5, 1, 2, 3} 之类的东西。我的计划是通过将索引移回comp() 内的位置来补偿旋转。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-03
  • 2015-04-15
  • 2013-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多