简体   繁体   中英

msvc std::lower_bound requires const operator*

I am getting a

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

it is thrown by this code in 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

The second line throws the error because of the const on the line above.

The iterator I am passing in, is a custom LegacyRandomAccessIterator over a "flat-file" and its operator* looks like this:

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

...

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

In other words, I can't just mark my operator* as const because it's not, and can't be really - It's doing loading of a buffered set of records from disk, and that's not a const operation in a the current design.

I implemented a "dummy" const version to prove that was the problem:

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

Error is gone, but clearly this doesn't do anything.

libstdc++ doesn't have this expectation of a const operator* . (I haven't tested libc++)

Is this solvable, without some major redesign of my iterator?

Is it reasonable for MSVC's implementation to have this expectation?

std::lower_bound takes a Cpp17ForwardIterator , which must also be a Cpp17InputIterator . The Cpp17InputIterator requirements include :

Expression Return type
*a reference , convertible to T

Here, a is a "value of type X or const X " , so MSVC is justified in requiring a const-qualified unary indirection operator; the "or" means that the code using the iterator can use either, and the author of the iterator has to support both. (Note that Cpp17InputIterator differs from Cpp17OutputIterator , where the required operation is *r = o , with r a non-const reference, X& .)

So your operator* should have const qualification, and return a reference; specifically, a reference to T or const T (this is a Cpp17ForwardIterator requirement ). You can satisfy this straightforwardly with using reference = const T& and by making cur_ and cur_valid_ mutable .

The use of mutable here is entirely legitimate; since operator*() const is idempotent, it is "logically const" and the modifications to the data members are non-observable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM