Skip to content

Commit

Permalink
P2836R1: basic_const_iterator Should Follow Its Underlying Type's C…
Browse files Browse the repository at this point in the history
…onvertibility (#4188)

Co-authored-by: Stephan T. Lavavej <[email protected]>
  • Loading branch information
JMazurkiewicz and StephanTLavavej authored Nov 17, 2023
1 parent 14a3d04 commit c343c8c
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 4 deletions.
13 changes: 13 additions & 0 deletions stl/inc/xutility
Original file line number Diff line number Diff line change
Expand Up @@ -2131,6 +2131,19 @@ public:
return _Current == _Se;
}

template <_Not_a_const_iterator _Other>
requires _Constant_iterator<_Other> && convertible_to<const _Iter&, _Other>
_NODISCARD constexpr operator _Other() const& noexcept(
is_nothrow_convertible_v<const _Iter&, _Other>) /* strengthened */ {
return _Current;
}

template <_Not_a_const_iterator _Other>
requires _Constant_iterator<_Other> && convertible_to<_Iter, _Other>
_NODISCARD constexpr operator _Other() && noexcept(is_nothrow_convertible_v<_Iter, _Other>) /* strengthened */ {
return _STD move(_Current);
}

_NODISCARD constexpr bool operator<(const basic_const_iterator& _Right) const
noexcept(noexcept(_Fake_copy_init<bool>(_Current < _Right._Current))) // strengthened
requires random_access_iterator<_Iter>
Expand Down
3 changes: 2 additions & 1 deletion stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@
// P2693R1 Formatting thread::id And stacktrace
// P2713R1 Escaping Improvements In std::format
// P2763R1 Fixing layout_stride's Default Constructor For Fully Static Extents
// P2836R1 basic_const_iterator Should Follow Its Underlying Type's Convertibility

// _HAS_CXX23 and _SILENCE_ALL_CXX23_DEPRECATION_WARNINGS control:
// P1413R3 Deprecate aligned_storage And aligned_union
Expand Down Expand Up @@ -1831,7 +1832,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect
#ifdef __cpp_lib_concepts
#define __cpp_lib_out_ptr 202106L
#define __cpp_lib_print 202207L
#define __cpp_lib_ranges_as_const 202207L
#define __cpp_lib_ranges_as_const 202311L
#define __cpp_lib_ranges_as_rvalue 202207L
#define __cpp_lib_ranges_cartesian_product 202207L
#define __cpp_lib_ranges_chunk 202202L
Expand Down
86 changes: 84 additions & 2 deletions tests/std/tests/P2278R4_basic_const_iterator/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,89 @@ constexpr void instantiation_test() {
instantiator::call<test_iterator<contiguous_iterator_tag, CanDifference::yes>>();
}

int main() {
static_assert((instantiation_test(), true));
template <class T>
class tracking_input_iterator {
public:
using value_type = remove_const_t<T>;
using difference_type = ptrdiff_t;

constexpr tracking_input_iterator() = default;

constexpr tracking_input_iterator(const tracking_input_iterator&) : copied{true} {}

constexpr tracking_input_iterator(tracking_input_iterator&&) : moved{true} {}

template <class U>
requires convertible_to<const U&, T>
constexpr tracking_input_iterator(const tracking_input_iterator<U>&) : copied{true} {}

template <class U>
requires convertible_to<U, T>
constexpr tracking_input_iterator(tracking_input_iterator<U>&&) : moved{true} {}

tracking_input_iterator& operator=(const tracking_input_iterator&) = default;
tracking_input_iterator& operator=(tracking_input_iterator&&) = default;

constexpr tracking_input_iterator& operator++(); // not defined
constexpr void operator++(int); // not defined
T& operator*() const; // not defined

constexpr bool is_copied() const {
return copied;
}

constexpr bool is_moved() const {
return moved;
}

private:
bool copied = false;
bool moved = false;
};

static_assert(input_iterator<tracking_input_iterator<int>>);
static_assert(!_Constant_iterator<tracking_input_iterator<int>>);
static_assert(_Constant_iterator<tracking_input_iterator<const int>>);

// P2836R1 basic_const_iterator Should Follow Its Underlying Type's Convertibility
constexpr void test_p2836r1() {
{ // Code from P2836R1
vector<int> v;
auto t = v | views::take_while([](const int x) { return x < 100; });
auto f = [](vector<int>::const_iterator) {};
auto i2 = ranges::cbegin(t);
f(i2); // Error before P2836R1
}

{
tracking_input_iterator<int> i;
basic_const_iterator ci{i};

tracking_input_iterator<const float> j1 = ci;
assert(j1.is_copied());
assert(!j1.is_moved());

tracking_input_iterator<const long> j2 = move(ci);
assert(!j2.is_copied());
assert(j2.is_moved());

// Incorrect conversions
static_assert(!constructible_from<tracking_input_iterator<void* const>, const decltype(ci)&>);
static_assert(!constructible_from<tracking_input_iterator<void* const>, decltype(ci)>);

// Non-const target iterator
static_assert(!constructible_from<tracking_input_iterator<float>, const decltype(ci)&>);
static_assert(!constructible_from<tracking_input_iterator<long>, decltype(ci)>);
}
}

constexpr bool all_tests() {
instantiation_test();
test_p2836r1();
return true;
}

int main() {
static_assert(all_tests());
all_tests();
}
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ STATIC_ASSERT(__cpp_lib_ranges == 202110L);
#endif

#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
STATIC_ASSERT(__cpp_lib_ranges_as_const == 202207L);
STATIC_ASSERT(__cpp_lib_ranges_as_const == 202311L);
#elif defined(__cpp_lib_ranges_as_const)
#error __cpp_lib_ranges_as_const is defined
#endif
Expand Down

0 comments on commit c343c8c

Please sign in to comment.