msvc std::lower_bound 需要 const 运算符*

msvc std::lower_bound requires const operator*

我得到一个

Error   C2678   binary '*': no operator found which takes a left-hand operand of type 'const _InIt' (or there is no acceptable conversion)

MSVC (2022, V17.1)中这段代码抛出<algorithm> header.

template <class _FwdIt, class _Ty, class _Pr>
_NODISCARD _CONSTEXPR20 _FwdIt lower_bound(_FwdIt _First, const _FwdIt _Last, const _Ty& _Val, _Pr _Pred) {

...
        const auto _UMid                   = _STD next(_UFirst, _Count2);
        if (_Pred(*_UMid, _Val)) { // try top half

第二行报错是因为上面一行的const

我传入的迭代器是一个基于“flat-file”的自定义 LegacyRandomAccessIterator,其 operator* 如下所示:

  value_type operator*() { return current(); }

...

  ValueType current() {
    if (!cur_valid_) {
      cur_       = ffdb_->get_record(pos_);
      cur_valid_ = true;
    }
    return cur_;
  }

换句话说,我不能只将我的 operator* 标记为 const 因为它不是,也不可能是 - 它正在从磁盘加载一组缓冲记录,这不是当前设计中的 const 操作。

我实现了一个“虚拟”const 版本来证明这是问题所在:

 value_type operator*() const { return value_type{}; }

错误消失了,但显然这没有任何作用。

libstdc++ 没有这种对 const operator* 的期望。 (我没有测试过 libc++)

如果不对我的迭代器进行一些重大的重新设计,这是否可以解决?

MSVC的实现有这个期望是否合理?

std::lower_bound 需要一个 Cpp17ForwardIterator,它也必须是一个 Cpp17InputIteratorCpp17InputIterator requirements include:

Expression Return type
*a reference, convertible to T

这里,a是一个"value of type X or const X",所以MSVC有理由要求const-qualified一元间接运算符; “或”意味着使用迭代器的代码可以使用其中一个,迭代器的作者必须支持两者。 (注意 Cpp17InputIterator 不同于 Cpp17OutputIterator,其中要求的操作是 *r = or 一个 non-const参考,X&.)

所以你的operator*应该有const资格,return有推荐信;具体来说,是对 Tconst T 的引用(这是 a Cpp17ForwardIterator requirement)。您可以使用 using reference = const T& 并使 cur_ cur_valid_ mutable.

直接满足此要求

这里使用mutable是完全合法的;因为 operator*() const 是幂等的,所以它是“逻辑常量”,对数据成员的修改是 non-observable.