-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc++] Move out flat_map::iterator
(for reusing it in flat_multimap)
#117445
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
Conversation
@llvm/pr-subscribers-libcxx Author: Hui (huixie90) ChangesFull diff: https://github.com/llvm/llvm-project/pull/117445.diff 8 Files Affected:
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 0ae031e5365aef..b37b00165fd6ac 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -358,6 +358,7 @@ set(files
__filesystem/space_info.h
__filesystem/u8path.h
__flat_map/flat_map.h
+ __flat_map/key_value_iterator.h
__flat_map/sorted_unique.h
__format/buffer.h
__format/concepts.h
diff --git a/libcxx/include/__flat_map/flat_map.h b/libcxx/include/__flat_map/flat_map.h
index 58b362ad7a706f..6bc8608ecf1902 100644
--- a/libcxx/include/__flat_map/flat_map.h
+++ b/libcxx/include/__flat_map/flat_map.h
@@ -23,11 +23,11 @@
#include <__algorithm/remove_if.h>
#include <__assert>
#include <__compare/synth_three_way.h>
-#include <__concepts/convertible_to.h>
#include <__concepts/swappable.h>
#include <__config>
#include <__cstddef/byte.h>
#include <__cstddef/ptrdiff_t.h>
+#include <__flat_map/key_value_iterator.h>
#include <__flat_map/sorted_unique.h>
#include <__functional/invoke.h>
#include <__functional/is_transparent.h>
@@ -38,7 +38,6 @@
#include <__iterator/next.h>
#include <__iterator/ranges_iterator_traits.h>
#include <__iterator/reverse_iterator.h>
-#include <__memory/addressof.h>
#include <__memory/allocator_traits.h>
#include <__memory/uses_allocator.h>
#include <__memory/uses_allocator_construction.h>
@@ -57,8 +56,8 @@
#include <__type_traits/is_allocator.h>
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_same.h>
-#include <__type_traits/maybe_const.h>
#include <__utility/exception_guard.h>
+#include <__utility/move.h>
#include <__utility/pair.h>
#include <__utility/scope_guard.h>
#include <__vector/vector.h>
@@ -82,8 +81,6 @@ template <class _Key,
class _KeyContainer = vector<_Key>,
class _MappedContainer = vector<_Tp>>
class flat_map {
- template <bool _Const>
- struct __iterator;
template <class, class, class, class, class>
friend class flat_map;
@@ -93,6 +90,9 @@ class flat_map {
static_assert(!is_same_v<_KeyContainer, std::vector<bool>>, "vector<bool> is not a sequence container");
static_assert(!is_same_v<_MappedContainer, std::vector<bool>>, "vector<bool> is not a sequence container");
+ template <bool _Const>
+ using __iterator = __key_value_iterator<flat_map, _KeyContainer, _MappedContainer, _Const>;
+
public:
// types
using key_type = _Key;
@@ -134,123 +134,6 @@ class flat_map {
_LIBCPP_HIDE_FROM_ABI static constexpr bool __is_compare_transparent = __is_transparent_v<_Compare, _Compare>;
- template <bool _Const>
- struct __iterator {
- private:
- using __key_iterator = ranges::iterator_t<const key_container_type>;
- using __mapped_iterator = ranges::iterator_t<__maybe_const<_Const, mapped_container_type>>;
- using __reference = pair<iter_reference_t<__key_iterator>, iter_reference_t<__mapped_iterator>>;
-
- struct __arrow_proxy {
- __reference __ref_;
- _LIBCPP_HIDE_FROM_ABI __reference* operator->() { return std::addressof(__ref_); }
- };
-
- __key_iterator __key_iter_;
- __mapped_iterator __mapped_iter_;
-
- friend flat_map;
-
- public:
- using iterator_concept = random_access_iterator_tag;
- // `flat_map::iterator` only satisfy "Cpp17InputIterator" named requirements, because
- // its `reference` is not a reference type.
- // However, to avoid surprising runtime behaviour when it is used with the
- // Cpp17 algorithms or operations, iterator_category is set to random_access_iterator_tag.
- using iterator_category = random_access_iterator_tag;
- using value_type = flat_map::value_type;
- using difference_type = flat_map::difference_type;
-
- _LIBCPP_HIDE_FROM_ABI __iterator() = default;
-
- _LIBCPP_HIDE_FROM_ABI __iterator(__iterator<!_Const> __i)
- requires _Const && convertible_to<ranges::iterator_t<key_container_type>, __key_iterator> &&
- convertible_to<ranges::iterator_t<mapped_container_type>, __mapped_iterator>
- : __key_iter_(std::move(__i.__key_iter_)), __mapped_iter_(std::move(__i.__mapped_iter_)) {}
-
- _LIBCPP_HIDE_FROM_ABI __iterator(__key_iterator __key_iter, __mapped_iterator __mapped_iter)
- : __key_iter_(std::move(__key_iter)), __mapped_iter_(std::move(__mapped_iter)) {}
-
- _LIBCPP_HIDE_FROM_ABI __reference operator*() const { return __reference(*__key_iter_, *__mapped_iter_); }
- _LIBCPP_HIDE_FROM_ABI __arrow_proxy operator->() const { return __arrow_proxy{**this}; }
-
- _LIBCPP_HIDE_FROM_ABI __iterator& operator++() {
- ++__key_iter_;
- ++__mapped_iter_;
- return *this;
- }
-
- _LIBCPP_HIDE_FROM_ABI __iterator operator++(int) {
- __iterator __tmp(*this);
- ++*this;
- return __tmp;
- }
-
- _LIBCPP_HIDE_FROM_ABI __iterator& operator--() {
- --__key_iter_;
- --__mapped_iter_;
- return *this;
- }
-
- _LIBCPP_HIDE_FROM_ABI __iterator operator--(int) {
- __iterator __tmp(*this);
- --*this;
- return __tmp;
- }
-
- _LIBCPP_HIDE_FROM_ABI __iterator& operator+=(difference_type __x) {
- __key_iter_ += __x;
- __mapped_iter_ += __x;
- return *this;
- }
-
- _LIBCPP_HIDE_FROM_ABI __iterator& operator-=(difference_type __x) {
- __key_iter_ -= __x;
- __mapped_iter_ -= __x;
- return *this;
- }
-
- _LIBCPP_HIDE_FROM_ABI __reference operator[](difference_type __n) const { return *(*this + __n); }
-
- _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) {
- return __x.__key_iter_ == __y.__key_iter_;
- }
-
- _LIBCPP_HIDE_FROM_ABI friend bool operator<(const __iterator& __x, const __iterator& __y) {
- return __x.__key_iter_ < __y.__key_iter_;
- }
-
- _LIBCPP_HIDE_FROM_ABI friend bool operator>(const __iterator& __x, const __iterator& __y) { return __y < __x; }
-
- _LIBCPP_HIDE_FROM_ABI friend bool operator<=(const __iterator& __x, const __iterator& __y) { return !(__y < __x); }
-
- _LIBCPP_HIDE_FROM_ABI friend bool operator>=(const __iterator& __x, const __iterator& __y) { return !(__x < __y); }
-
- _LIBCPP_HIDE_FROM_ABI friend auto operator<=>(const __iterator& __x, const __iterator& __y)
- requires three_way_comparable<__key_iterator>
- {
- return __x.__key_iter_ <=> __y.__key_iter_;
- }
-
- _LIBCPP_HIDE_FROM_ABI friend __iterator operator+(const __iterator& __i, difference_type __n) {
- auto __tmp = __i;
- __tmp += __n;
- return __tmp;
- }
-
- _LIBCPP_HIDE_FROM_ABI friend __iterator operator+(difference_type __n, const __iterator& __i) { return __i + __n; }
-
- _LIBCPP_HIDE_FROM_ABI friend __iterator operator-(const __iterator& __i, difference_type __n) {
- auto __tmp = __i;
- __tmp -= __n;
- return __tmp;
- }
-
- _LIBCPP_HIDE_FROM_ABI friend difference_type operator-(const __iterator& __x, const __iterator& __y) {
- return difference_type(__x.__key_iter_ - __y.__key_iter_);
- }
- };
-
public:
// [flat.map.cons], construct/copy/destroy
_LIBCPP_HIDE_FROM_ABI flat_map() noexcept(
@@ -1309,20 +1192,20 @@ template <ranges::input_range _Range,
class = __enable_if_t<!__is_allocator<_Compare>::value && __is_allocator<_Allocator>::value>>
flat_map(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator())
-> flat_map<
- __range_key_type<_Range>,
- __range_mapped_type<_Range>,
- _Compare,
- vector<__range_key_type<_Range>, __allocator_traits_rebind_t<_Allocator, __range_key_type<_Range>>>,
- vector<__range_mapped_type<_Range>, __allocator_traits_rebind_t<_Allocator, __range_mapped_type<_Range>>>>;
+ __range_key_type<_Range>,
+ __range_mapped_type<_Range>,
+ _Compare,
+ vector<__range_key_type<_Range>, __allocator_traits_rebind_t<_Allocator, __range_key_type<_Range>>>,
+ vector<__range_mapped_type<_Range>, __allocator_traits_rebind_t<_Allocator, __range_mapped_type<_Range>>>>;
template <ranges::input_range _Range, class _Allocator, class = __enable_if_t<__is_allocator<_Allocator>::value>>
flat_map(from_range_t, _Range&&, _Allocator)
-> flat_map<
- __range_key_type<_Range>,
- __range_mapped_type<_Range>,
- less<__range_key_type<_Range>>,
- vector<__range_key_type<_Range>, __allocator_traits_rebind_t<_Allocator, __range_key_type<_Range>>>,
- vector<__range_mapped_type<_Range>, __allocator_traits_rebind_t<_Allocator, __range_mapped_type<_Range>>>>;
+ __range_key_type<_Range>,
+ __range_mapped_type<_Range>,
+ less<__range_key_type<_Range>>,
+ vector<__range_key_type<_Range>, __allocator_traits_rebind_t<_Allocator, __range_key_type<_Range>>>,
+ vector<__range_mapped_type<_Range>, __allocator_traits_rebind_t<_Allocator, __range_mapped_type<_Range>>>>;
template <class _Key, class _Tp, class _Compare = less<_Key>>
requires(!__is_allocator<_Compare>::value)
diff --git a/libcxx/include/__flat_map/key_value_iterator.h b/libcxx/include/__flat_map/key_value_iterator.h
new file mode 100644
index 00000000000000..a88ab1bbce32af
--- /dev/null
+++ b/libcxx/include/__flat_map/key_value_iterator.h
@@ -0,0 +1,170 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___FLAT_MAP_KEY_VALUE_ITERATOR_H
+#define _LIBCPP___FLAT_MAP_KEY_VALUE_ITERATOR_H
+
+#include <__compare/three_way_comparable.h>
+#include <__concepts/convertible_to.h>
+#include <__config>
+#include <__iterator/iterator_traits.h>
+#include <__memory/addressof.h>
+#include <__ranges/access.h>
+#include <__type_traits/maybe_const.h>
+#include <__utility/move.h>
+#include <__utility/pair.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 23
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Owner, class _KeyContainer, class _MappedContainer, bool _Const>
+struct __key_value_iterator {
+private:
+ using __key_iterator = ranges::iterator_t<const _KeyContainer>;
+ using __mapped_iterator = ranges::iterator_t<__maybe_const<_Const, _MappedContainer>>;
+ using __reference = pair<iter_reference_t<__key_iterator>, iter_reference_t<__mapped_iterator>>;
+
+ struct __arrow_proxy {
+ __reference __ref_;
+ _LIBCPP_HIDE_FROM_ABI __reference* operator->() { return std::addressof(__ref_); }
+ };
+
+ __key_iterator __key_iter_;
+ __mapped_iterator __mapped_iter_;
+
+ friend _Owner;
+
+ template <class, class, class, bool>
+ friend struct __key_value_iterator;
+
+public:
+ using iterator_concept = random_access_iterator_tag;
+ // `flat_map::iterator` only satisfy "Cpp17InputIterator" named requirements, because
+ // its `reference` is not a reference type.
+ // However, to avoid surprising runtime behaviour when it is used with the
+ // Cpp17 algorithms or operations, iterator_category is set to random_access_iterator_tag.
+ using iterator_category = random_access_iterator_tag;
+ using value_type = typename _Owner::value_type;
+ using difference_type = typename _Owner::difference_type;
+
+ _LIBCPP_HIDE_FROM_ABI __key_value_iterator() = default;
+
+ _LIBCPP_HIDE_FROM_ABI __key_value_iterator(__key_value_iterator<_Owner, _KeyContainer, _MappedContainer, !_Const> __i)
+ requires _Const && convertible_to<ranges::iterator_t<_KeyContainer>, __key_iterator> &&
+ convertible_to<ranges::iterator_t<_MappedContainer>, __mapped_iterator>
+ : __key_iter_(std::move(__i.__key_iter_)), __mapped_iter_(std::move(__i.__mapped_iter_)) {}
+
+ _LIBCPP_HIDE_FROM_ABI __key_value_iterator(__key_iterator __key_iter, __mapped_iterator __mapped_iter)
+ : __key_iter_(std::move(__key_iter)), __mapped_iter_(std::move(__mapped_iter)) {}
+
+ _LIBCPP_HIDE_FROM_ABI __reference operator*() const { return __reference(*__key_iter_, *__mapped_iter_); }
+ _LIBCPP_HIDE_FROM_ABI __arrow_proxy operator->() const { return __arrow_proxy{**this}; }
+
+ _LIBCPP_HIDE_FROM_ABI __key_value_iterator& operator++() {
+ ++__key_iter_;
+ ++__mapped_iter_;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI __key_value_iterator operator++(int) {
+ __key_value_iterator __tmp(*this);
+ ++*this;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI __key_value_iterator& operator--() {
+ --__key_iter_;
+ --__mapped_iter_;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI __key_value_iterator operator--(int) {
+ __key_value_iterator __tmp(*this);
+ --*this;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI __key_value_iterator& operator+=(difference_type __x) {
+ __key_iter_ += __x;
+ __mapped_iter_ += __x;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI __key_value_iterator& operator-=(difference_type __x) {
+ __key_iter_ -= __x;
+ __mapped_iter_ -= __x;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI __reference operator[](difference_type __n) const { return *(*this + __n); }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+ operator==(const __key_value_iterator& __x, const __key_value_iterator& __y) {
+ return __x.__key_iter_ == __y.__key_iter_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend bool operator<(const __key_value_iterator& __x, const __key_value_iterator& __y) {
+ return __x.__key_iter_ < __y.__key_iter_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend bool operator>(const __key_value_iterator& __x, const __key_value_iterator& __y) {
+ return __y < __x;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend bool operator<=(const __key_value_iterator& __x, const __key_value_iterator& __y) {
+ return !(__y < __x);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend bool operator>=(const __key_value_iterator& __x, const __key_value_iterator& __y) {
+ return !(__x < __y);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend auto operator<=>(const __key_value_iterator& __x, const __key_value_iterator& __y)
+ requires three_way_comparable<__key_iterator>
+ {
+ return __x.__key_iter_ <=> __y.__key_iter_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend __key_value_iterator operator+(const __key_value_iterator& __i, difference_type __n) {
+ auto __tmp = __i;
+ __tmp += __n;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend __key_value_iterator operator+(difference_type __n, const __key_value_iterator& __i) {
+ return __i + __n;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend __key_value_iterator operator-(const __key_value_iterator& __i, difference_type __n) {
+ auto __tmp = __i;
+ __tmp -= __n;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend difference_type
+ operator-(const __key_value_iterator& __x, const __key_value_iterator& __y) {
+ return difference_type(__x.__key_iter_ - __y.__key_iter_);
+ }
+};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___FLAT_MAP_KEY_VALUE_ITERATOR_H
diff --git a/libcxx/include/flat_map b/libcxx/include/flat_map
index 15d79dd1ddca34..e96af677a7eed9 100644
--- a/libcxx/include/flat_map
+++ b/libcxx/include/flat_map
@@ -40,6 +40,7 @@ namespace std {
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <__flat_map/flat_map.h>
+#include <__flat_map/key_value_iterator.h>
#include <__flat_map/sorted_unique.h>
#include <version>
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 4e06a68c6a6b61..52e13aebc2187c 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1229,6 +1229,7 @@ module std [system] {
module flat_map {
module flat_map { header "__flat_map/flat_map.h" }
+ module key_value_iterator { header "__flat_map/key_value_iterator.h" }
module sorted_unique { header "__flat_map/sorted_unique.h" }
header "flat_map"
diff --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.cons/iter_iter_stability.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.cons/iter_iter_stability.pass.cpp
index 1ce859f6c737ea..14189840ce6605 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.cons/iter_iter_stability.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.cons/iter_iter_stability.pass.cpp
@@ -23,6 +23,7 @@
#include <flat_map>
#include <random>
#include <map>
+#include <vector>
#include "test_macros.h"
diff --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.iterators/reverse_iterator.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.iterators/reverse_iterator.pass.cpp
index 09e18986a7e813..fc3949d70745fc 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.iterators/reverse_iterator.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.iterators/reverse_iterator.pass.cpp
@@ -23,7 +23,7 @@
#include <deque>
#include <flat_map>
#include <functional>
-#include <string>
+#include <vector>
#include <iterator>
diff --git a/libcxx/test/std/containers/container.adaptors/flat.map/incomplete_type.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/incomplete_type.pass.cpp
index 81c590ba73a157..76461951f0d3d8 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/incomplete_type.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/incomplete_type.pass.cpp
@@ -14,6 +14,7 @@
// type.
#include <flat_map>
+#include <vector>
struct A {
using Map = std::flat_map<A, A>;
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
a3dadd6
to
9dc6f16
Compare
flat_map::iterator
(for reusing it in flat_multimap)
9dc6f16
to
02ca7a6
Compare
|
||
_LIBCPP_BEGIN_NAMESPACE_STD | ||
|
||
template <class _Owner, class _KeyContainer, class _MappedContainer, bool _Const> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it intended that two different flat_(multi)map
specializations never have the same iterator types (i.e. the design is completely non-SCARY)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a requirement to provide SCARY iterators? I think there were some types that were required to provide SCARY iterators since C++11, but my memory is failing me. I'm not certain if there is some library-wide requirement about this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a requirement to provide SCARY iterators? I think there were some types that were required to provide SCARY iterators since C++11, but my memory is failing me. I'm not certain if there is some library-wide requirement about this?
No. N2980 proposed requiring SCARY, but it was effectively rejected (per LWG1242). Currently SCARY-ness is totally part of quality of implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
had discussion with @ldionne, we definitely don't want to allow flat_map
and flat_multimap
's iterator to be interchangeable. Supporting SCARY iterators would allow erroneous programs which can be easily caught at compile time otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ Or at least, that's our current thinking. We're open to being persuaded otherwise but our thinking was that if a user has the bad luck of unintendedly mixing up flat_map::iterator
with flat_multimap::iterator
, they'd rather know that at compile-time. IOW, not providing SCARY iterators seems like a feature more than a QOI deficiency in this situation. As I said, that's just our current thinking and it can evolve.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ldionne We could be a little bit SCARY where we don' allow the mix of flat_map
and flat_multimap
. But we can allow the mix of flat_map<int, int, std::less<int>>::iterator
with flat_map<int, int, std::greater<int>>::iterator
. (The benefit is less number of template instantiations but one could also argue this is a bug rather than a feature). That is what we did for map
https://godbolt.org/z/57zTGoGd3
To achieve this, we could do something like
template <class _Tag,
class _KeyContainer,
class _MappedContainer,
class _Reference,
class _ConstReference,
class _ValueType,
class _DifferenceType,
bool _Const>
struct __key_value_iterator
where _Tag
can be __flat_map_tag
or __flat_multimap_tag
However, I am not a big fan of SCARY iterators. I think it is a Non-QoI rather than a QoI. The mix of those iterators are extremely likely a bug in the user code where we could easily detect at compile time. SCARY iterators simply allow the erroneous user code which against making C++ a safe language initiative.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In https://devblogs.microsoft.com/cppblog/what-are-scary-iterators/, they make a point that e.g. different allocators should probably not result in different iterators. That makes some sense to me, although I guess it depends what the pointer type is. But here it seems like the amount of stuff we need to cary around in __key_value_iterator
is probably not worth it.
02ca7a6
to
a1ae892
Compare
No description provided.