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.