-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
<vector>
: vector<bool>::iterator
fails to meet Cpp17InputIterator requirements
#5002
Comments
I agree that the input iterator requirements imply that |
We talked about this at the weekly maintainer meeting. "If none of the major implementations have done this in the last 25 years, it honestly couldn't be that big of a deal." - @CaseyCarter It would probably be possible to make this work, but in any event we want to send this to LWG and have them decide what to do. |
Indeed, the semantic equivalence between IMO a reasonable resolution would be just requiring this when |
That's partially the reason, yes. The other part was "generic code doesn't know the names of your type's members, so it's weird for generic code to require This was also the motivation for deprecating
Ha! I should have finished reading this before typing my response. |
For reference, making Click to expand proof-of-nerdsnipe diffdiff --git a/stl/inc/vector b/stl/inc/vector
index ef19788a..15718f01 100644
--- a/stl/inc/vector
+++ b/stl/inc/vector
@@ -2418,6 +2418,10 @@ public:
this->_Adopt(_Mypvbool);
}
+ _CONSTEXPR20 void flip() noexcept {
+ *const_cast<_Vbase*>(_Getptr()) ^= _Mask();
+ }
+
_CONSTEXPR20 void _Advance(_Size_type _Off) noexcept {
_Myoff += _Off;
_Myptr += _Myoff / _VBITS;
@@ -2430,6 +2434,24 @@ public:
}
#endif // _ITERATOR_DEBUG_LEVEL != 0
+ _CONSTEXPR20 void _Check_dereferenceable() const noexcept {
+#if _ITERATOR_DEBUG_LEVEL != 0
+ const auto _Cont = static_cast<const _Mycont*>(_Getcont());
+ _STL_VERIFY(_Cont, "cannot dereference value-initialized vector<bool> iterator");
+ _STL_VERIFY(_Total_off(_Cont) <= static_cast<_Difference_type>(_Cont->_Mysize),
+ "vector<bool> iterator not dereferenceable");
+#endif // _ITERATOR_DEBUG_LEVEL != 0
+ }
+
+ _CONSTEXPR20 const _Vbase* _Getptr() const noexcept {
+ _Check_dereferenceable();
+ return _Myptr;
+ }
+
+ _CONSTEXPR20 _Vbase _Mask() const noexcept {
+ return static_cast<_Vbase>(1) << _Myoff;
+ }
+
const _Vbase* _Myptr = nullptr;
_Size_type _Myoff = 0;
};
@@ -2445,6 +2467,9 @@ private:
// TRANSITION, ABI: non-trivial constructor
_CONSTEXPR20 _Vb_reference() = default;
+ using _Mybase::_Getptr;
+ using _Mybase::_Mask;
+
public:
_CONSTEXPR20 _Vb_reference(const _Vb_reference&) = default;
@@ -2477,39 +2502,19 @@ public:
}
#endif // _HAS_CXX23
- _CONSTEXPR20 void flip() noexcept {
- *const_cast<_Vbase*>(_Getptr()) ^= _Mask();
- }
-
_CONSTEXPR20 operator bool() const noexcept {
return (*_Getptr() & _Mask()) != 0;
}
- _CONSTEXPR20 const _Vbase* _Getptr() const noexcept {
-#if _ITERATOR_DEBUG_LEVEL != 0
- const auto _Cont = static_cast<const _Mycont*>(this->_Getcont());
- _STL_VERIFY(_Cont, "cannot dereference value-initialized vector<bool> iterator");
- _STL_VERIFY(this->_Total_off(_Cont) <= static_cast<_Difference_type>(_Cont->_Mysize),
- "vector<bool> iterator not dereferenceable");
-#endif // _ITERATOR_DEBUG_LEVEL != 0
-
- return this->_Myptr;
- }
-
friend _CONSTEXPR20 void swap(_Vb_reference _Left, _Vb_reference _Right) noexcept {
bool _Val = _Left; // NOT _STD swap
_Left = _Right;
_Right = _Val;
}
-
-protected:
- _CONSTEXPR20 _Vbase _Mask() const noexcept {
- return static_cast<_Vbase>(1) << this->_Myoff;
- }
};
template <class _Alvbase_wrapped>
-class _Vb_const_iterator : public _Vb_iter_base<_Alvbase_wrapped> {
+class _Vb_const_iterator : protected _Vb_iter_base<_Alvbase_wrapped> {
public:
using _Mybase = _Vb_iter_base<_Alvbase_wrapped>;
using _Mycont = typename _Mybase::_Mycont;
@@ -2520,7 +2525,7 @@ public:
using iterator_category = random_access_iterator_tag;
using value_type = bool;
using difference_type = typename _Mybase::_Difference_type;
- using pointer = const_reference*;
+ using pointer = void;
using reference = const_reference;
_CONSTEXPR20 _Vb_const_iterator() = default;
@@ -2529,13 +2534,7 @@ public:
: _Mybase(_Ptr, 0, _Mypvbool) {}
_NODISCARD _CONSTEXPR20 const_reference operator*() const noexcept {
-#if _ITERATOR_DEBUG_LEVEL != 0
- const auto _Cont = static_cast<const _Mycont*>(this->_Getcont());
- _STL_VERIFY(_Cont, "cannot dereference value-initialized vector<bool> iterator");
- _STL_VERIFY(this->_Total_off(_Cont) < static_cast<difference_type>(_Cont->_Mysize),
- "vector<bool> iterator not dereferenceable");
-#endif // _ITERATOR_DEBUG_LEVEL != 0
-
+ this->_Check_dereferenceable();
return _Reft(*this);
}
@@ -2718,22 +2717,21 @@ public:
using iterator_category = random_access_iterator_tag;
using value_type = bool;
using difference_type = typename _Mybase::difference_type;
- using pointer = _Reft*;
+ using pointer = _Vb_iter_base<_Alvbase_wrapped>*;
using reference = _Reft;
using _Mybase::_Mybase;
_NODISCARD _CONSTEXPR20 reference operator*() const noexcept {
-#if _ITERATOR_DEBUG_LEVEL != 0
- const auto _Cont = static_cast<const _Mycont*>(this->_Getcont());
- _STL_VERIFY(_Cont, "cannot dereference value-initialized vector<bool> iterator");
- _STL_VERIFY(this->_Total_off(_Cont) < static_cast<difference_type>(_Cont->_Mysize),
- "vector<bool> iterator not dereferenceable");
-#endif // _ITERATOR_DEBUG_LEVEL != 0
-
+ this->_Check_dereferenceable();
return _Reft(*this);
}
+ _NODISCARD _CONSTEXPR20 pointer operator->() const noexcept {
+ this->_Check_dereferenceable();
+ return const_cast<_Vb_iterator*>(this);
+ }
+
_CONSTEXPR20 _Vb_iterator& operator++() noexcept {
_Mybase::operator++();
return *this; Caveat emptor, I didn't test anything but the repro. Another question here - |
[iterator.cpp17.general]/1 only says But some readers seemingly thought more things are required to be supported, see LWG-659 & LLVM-111032. Perhaps it would be better to add a note? |
Aha! Yes, thanks. I missed that subtlety. And thanks for the reminder about LWG-659, which was reverted by LWG-2790. Swinging back to the original issue, to me the error here isn't the implementations but the iterator requirements being wrong for proxy reference types. My intuition tells me that Honestly, |
Describe the bug
The following program doesn't compile.
It's probably intended that
(*vb.begin()).flip()
works and is equivalent tovb[0].flip()
. As per [tab:inputiterator], it seems thatvb.begin()->flip()
also needs to be supported.Command-line test case
Godbolt link
Expected behavior
vb.begin()->flip()
works and is equivalent tovb[0].flip()
.STL version
(Probably in all existing versions.)
Additional context
We may need to correspondingly change member type
pointer
to conform to [iterator.traits]/1.Also, it's even not very clear to me that
vector<bool>::iterator
is required to meet the Cpp17InputIterator named requirements. Givenvector<bool>
is not a real container, it's unclear which requirements on iterators of containers are applied to iterators ofvector<bool>
. LWG-1422 is related.The text was updated successfully, but these errors were encountered: