[libc++] Remove random [[nodiscard]] in the test suite

This commit is contained in:
Louis Dionne 2021-07-12 12:31:51 -04:00
parent ef49d925e2
commit 88b73a980f
28 changed files with 97 additions and 97 deletions

View File

@ -27,13 +27,13 @@ struct R {
// clang-format off
template<class F, class T, class U>
requires std::relation<F, T, U>
[[nodiscard]] constexpr bool check_equivalence_relation_subsumes_relation() {
constexpr bool check_equivalence_relation_subsumes_relation() {
return false;
}
template<class F, class T, class U>
requires std::equivalence_relation<F, T, U> && true
[[nodiscard]] constexpr bool check_equivalence_relation_subsumes_relation() {
constexpr bool check_equivalence_relation_subsumes_relation() {
return true;
}
// clang-format on
@ -48,13 +48,13 @@ static_assert(check_equivalence_relation_subsumes_relation<R, S1, S2>());
// clang-format off
template<class F, class T, class U>
requires std::relation<F, T, U> && true
[[nodiscard]] constexpr bool check_relation_subsumes_equivalence_relation() {
constexpr bool check_relation_subsumes_equivalence_relation() {
return true;
}
template<class F, class T, class U>
requires std::equivalence_relation<F, T, U>
[[nodiscard]] constexpr bool check_relation_subsumes_equivalence_relation() {
constexpr bool check_relation_subsumes_equivalence_relation() {
return false;
}
// clang-format on
@ -69,13 +69,13 @@ static_assert(check_relation_subsumes_equivalence_relation<R, S1, S2>());
// clang-format off
template<class F, class T, class U>
requires std::equivalence_relation<F, T, T> && std::equivalence_relation<F, U, U>
[[nodiscard]] constexpr bool check_equivalence_relation_subsumes_itself() {
constexpr bool check_equivalence_relation_subsumes_itself() {
return false;
}
template<class F, class T, class U>
requires std::equivalence_relation<F, T, U>
[[nodiscard]] constexpr bool check_equivalence_relation_subsumes_itself() {
constexpr bool check_equivalence_relation_subsumes_itself() {
return true;
}
// clang-format on

View File

@ -17,15 +17,15 @@
// clang-format off
template<class F, class T, class U>
requires std::relation<F, T, U>
[[nodiscard]] constexpr bool check_subsumption() { return false; }
constexpr bool check_subsumption() { return false; }
template<class F, class T>
requires std::equivalence_relation<F, T, T> && true
[[nodiscard]] constexpr bool check_subsumption() { return false; }
constexpr bool check_subsumption() { return false; }
template<class F, class T, class U>
requires std::equivalence_relation<F, T, U> && true
[[nodiscard]] constexpr bool check_subsumption() { return true; }
constexpr bool check_subsumption() { return true; }
// clang-format on
static_assert(check_subsumption<int (*)(int, int), int, int>());
@ -46,11 +46,11 @@ static_assert(check_subsumption<R, S1, S2>());
// clang-format off
template<class F, class T, class U>
requires std::relation<F, T, U> && true
[[nodiscard]] constexpr bool check_reverse_subsumption() { return true; }
constexpr bool check_reverse_subsumption() { return true; }
template<class F, class T, class U>
requires std::equivalence_relation<F, T, U>
[[nodiscard]] constexpr bool check_no_subsumption() { return false; }
constexpr bool check_no_subsumption() { return false; }
// clang-format on
static_assert(check_reverse_subsumption<int (*)(int, int), int, int>());

View File

@ -19,7 +19,7 @@
#include <type_traits>
template <class R, class... Args>
[[nodiscard]] constexpr bool check_invocable() {
constexpr bool check_invocable() {
constexpr bool result = std::invocable<R(Args...), Args...>;
static_assert(std::invocable<R(Args...) noexcept, Args...> == result);
static_assert(std::invocable<R (*)(Args...), Args...> == result);
@ -239,7 +239,7 @@ static_assert(!std::invocable<multiple_overloads, multiple_overloads::O>);
namespace pointer_to_member_functions {
// clang-format off
template<class Member, class T, class... Args>
[[nodiscard]] constexpr bool check_member_is_invocable()
constexpr bool check_member_is_invocable()
{
constexpr bool result = std::invocable<Member, T, Args...>;
using uncv_t = std::remove_cvref_t<T>;

View File

@ -45,9 +45,9 @@ static_assert(std::predicate<Predicate&, int, double, char>);
static_assert(!std::predicate<const Predicate, int, double, char>);
static_assert(!std::predicate<const Predicate&, int, double, char>);
[[nodiscard]] constexpr bool check_lambda(auto) { return false; }
constexpr bool check_lambda(auto) { return false; }
[[nodiscard]] constexpr bool check_lambda(std::predicate auto) { return true; }
constexpr bool check_lambda(std::predicate auto) { return true; }
static_assert(check_lambda([] { return std::true_type(); }));
static_assert(check_lambda([]() -> int* { return nullptr; }));

View File

@ -45,9 +45,9 @@ static_assert(std::predicate<Predicate&, int, double, char>);
static_assert(!std::predicate<const Predicate, int, double, char>);
static_assert(!std::predicate<const Predicate&, int, double, char>);
[[nodiscard]] constexpr bool check_lambda(auto) { return false; }
constexpr bool check_lambda(auto) { return false; }
[[nodiscard]] constexpr bool check_lambda(std::predicate auto) { return true; }
constexpr bool check_lambda(std::predicate auto) { return true; }
static_assert(check_lambda([] { return std::true_type(); }));
static_assert(check_lambda([]() -> int* { return nullptr; }));

View File

@ -14,14 +14,14 @@
#include <concepts>
[[nodiscard]] constexpr bool check_subsumption(std::regular_invocable auto) {
constexpr bool check_subsumption(std::regular_invocable auto) {
return false;
}
// clang-format off
template<class F>
requires std::predicate<F> && true
[[nodiscard]] constexpr bool check_subsumption(F)
constexpr bool check_subsumption(F)
{
return true;
}

View File

@ -14,14 +14,14 @@
#include <concepts>
[[nodiscard]] constexpr bool check_subsumption(std::regular_invocable auto) {
constexpr bool check_subsumption(std::regular_invocable auto) {
return false;
}
// clang-format off
template<class F>
requires std::predicate<F> && true
[[nodiscard]] constexpr bool check_subsumption(F)
constexpr bool check_subsumption(F)
{
return true;
}

View File

@ -19,7 +19,7 @@
#include <type_traits>
template <class R, class... Args>
[[nodiscard]] constexpr bool check_invocable() {
constexpr bool check_invocable() {
constexpr bool result = std::regular_invocable<R(Args...), Args...>;
static_assert(std::regular_invocable<R(Args...) noexcept, Args...> == result);
static_assert(std::regular_invocable<R (*)(Args...), Args...> == result);
@ -265,7 +265,7 @@ static_assert(!std::regular_invocable<multiple_overloads, multiple_overloads::O>
namespace pointer_to_member_functions {
// clang-format off
template<class Member, class T, class... Args>
[[nodiscard]] constexpr bool check_member_is_invocable()
constexpr bool check_member_is_invocable()
{
constexpr bool result = std::regular_invocable<Member, T, Args...>;
using uncv_t = std::remove_cvref_t<T>;

View File

@ -28,13 +28,13 @@ struct R {
template<class F, class T, class U>
requires std::predicate<F, T, T> && std::predicate<F, T, U> &&
std::predicate<F, U, T> && std::predicate<F, U, U>
[[nodiscard]] constexpr bool check_relation_subsumes_predicate() {
constexpr bool check_relation_subsumes_predicate() {
return false;
}
template<class F, class T, class U>
requires std::relation<F, T, U> && true
[[nodiscard]] constexpr bool check_relation_subsumes_predicate() {
constexpr bool check_relation_subsumes_predicate() {
return true;
}
// clang-format on
@ -49,13 +49,13 @@ static_assert(check_relation_subsumes_predicate<R, S1, S2>());
// clang-format off
template<class F, class T, class U>
requires std::relation<F, T, T> && std::relation<F, U, U>
[[nodiscard]] constexpr bool check_relation_subsumes_itself() {
constexpr bool check_relation_subsumes_itself() {
return false;
}
template<class F, class T, class U>
requires std::relation<F, T, U>
[[nodiscard]] constexpr bool check_relation_subsumes_itself() {
constexpr bool check_relation_subsumes_itself() {
return true;
}
// clang-format on

View File

@ -18,11 +18,11 @@
template<class F, class T, class U>
requires std::predicate<F, T, T> && std::predicate<F, T, U> &&
std::predicate<F, U, T> && std::predicate<F, U, U>
[[nodiscard]] constexpr bool check_subsumption() { return false; }
constexpr bool check_subsumption() { return false; }
template<class F, class T, class U>
requires std::relation<F, T, U> && true
[[nodiscard]] constexpr bool check_subsumption() { return true; }
constexpr bool check_subsumption() { return true; }
// clang-format on
static_assert(check_subsumption<int (*)(int, double), int, double>());

View File

@ -27,13 +27,13 @@ struct R {
// clang-format off
template<class F, class T, class U>
requires std::relation<F, T, U>
[[nodiscard]] constexpr bool check_strict_weak_order_subsumes_relation() {
constexpr bool check_strict_weak_order_subsumes_relation() {
return false;
}
template<class F, class T, class U>
requires std::strict_weak_order<F, T, U> && true
[[nodiscard]] constexpr bool check_strict_weak_order_subsumes_relation() {
constexpr bool check_strict_weak_order_subsumes_relation() {
return true;
}
// clang-format on
@ -48,13 +48,13 @@ static_assert(check_strict_weak_order_subsumes_relation<R, S1, S2>());
// clang-format off
template<class F, class T, class U>
requires std::relation<F, T, U> && true
[[nodiscard]] constexpr bool check_relation_subsumes_strict_weak_order() {
constexpr bool check_relation_subsumes_strict_weak_order() {
return true;
}
template<class F, class T, class U>
requires std::strict_weak_order<F, T, U>
[[nodiscard]] constexpr bool check_relation_subsumes_strict_weak_order() {
constexpr bool check_relation_subsumes_strict_weak_order() {
return false;
}
// clang-format on
@ -69,13 +69,13 @@ static_assert(check_relation_subsumes_strict_weak_order<R, S1, S2>());
// clang-format off
template<class F, class T, class U>
requires std::strict_weak_order<F, T, T> && std::strict_weak_order<F, U, U>
[[nodiscard]] constexpr bool check_strict_weak_order_subsumes_itself() {
constexpr bool check_strict_weak_order_subsumes_itself() {
return false;
}
template<class F, class T, class U>
requires std::strict_weak_order<F, T, U>
[[nodiscard]] constexpr bool check_strict_weak_order_subsumes_itself() {
constexpr bool check_strict_weak_order_subsumes_itself() {
return true;
}
// clang-format on

View File

@ -17,11 +17,11 @@
// clang-format off
template<class F, class T, class U>
requires std::relation<F, T, U>
[[nodiscard]] constexpr bool check_subsumption() { return false; }
constexpr bool check_subsumption() { return false; }
template<class F, class T, class U>
requires std::strict_weak_order<F, T, U> && true
[[nodiscard]] constexpr bool check_subsumption() { return true; }
constexpr bool check_subsumption() { return true; }
// clang-format on
static_assert(check_subsumption<int (*)(int, double), int, double>());

View File

@ -671,7 +671,7 @@ struct Proxy {
constexpr Proxy proxy(A& a) { return Proxy{a}; }
} // namespace N
[[nodiscard]] constexpr bool CheckRegression() {
constexpr bool CheckRegression() {
int i = 1, j = 2;
lv_swap(i, j);
assert(i == 2 && j == 1);

View File

@ -12,20 +12,20 @@
// This overload should never be called. It exists solely to force subsumption.
template <std::integral I>
[[nodiscard]] constexpr bool CheckSubsumption(I) {
constexpr bool CheckSubsumption(I) {
return false;
}
// clang-format off
template <std::integral I>
requires std::signed_integral<I> && (!std::unsigned_integral<I>)
[[nodiscard]] constexpr bool CheckSubsumption(I) {
constexpr bool CheckSubsumption(I) {
return std::is_signed_v<I>;
}
template <std::integral I>
requires std::unsigned_integral<I> && (!std::signed_integral<I>)
[[nodiscard]] constexpr bool CheckSubsumption(I) {
constexpr bool CheckSubsumption(I) {
return std::is_unsigned_v<I>;
}
// clang-format on

View File

@ -161,7 +161,7 @@ static_assert(!std::regular<const_copy_assignment const>);
static_assert(!std::regular<cv_copy_assignment const volatile>);
struct is_equality_comparable {
[[nodiscard]] bool operator==(is_equality_comparable const&) const = default;
bool operator==(is_equality_comparable const&) const = default;
};
static_assert(std::regular<is_equality_comparable>);

View File

@ -20,7 +20,7 @@
#include <vector>
template <class T, class Expected>
[[nodiscard]] constexpr bool check_iter_value_t() {
constexpr bool check_iter_value_t() {
constexpr bool result = std::same_as<std::iter_value_t<T>, Expected>;
static_assert(std::same_as<std::iter_value_t<T const>, Expected> == result);
static_assert(std::same_as<std::iter_value_t<T volatile>, Expected> == result);
@ -50,13 +50,13 @@ static_assert(check_iter_value_t<both_members, double>());
// clang-format off
template <class T>
requires requires { typename std::iter_value_t<T>; }
[[nodiscard]] constexpr bool check_no_iter_value_t() {
constexpr bool check_no_iter_value_t() {
return false;
}
// clang-format on
template <class T>
[[nodiscard]] constexpr bool check_no_iter_value_t() {
constexpr bool check_no_iter_value_t() {
return true;
}

View File

@ -18,12 +18,12 @@
// clang-format off
template<std::input_iterator>
[[nodiscard]] constexpr bool check_subsumption() {
constexpr bool check_subsumption() {
return false;
}
template<std::forward_iterator>
[[nodiscard]] constexpr bool check_subsumption() {
constexpr bool check_subsumption() {
return true;
}
// clang-format on

View File

@ -20,12 +20,12 @@
// clang-format off
template<std::weakly_incrementable I>
requires std::regular<I>
[[nodiscard]] constexpr bool check_subsumption() {
constexpr bool check_subsumption() {
return false;
}
template<std::incrementable>
[[nodiscard]] constexpr bool check_subsumption() {
constexpr bool check_subsumption() {
return true;
}
// clang-format on

View File

@ -20,12 +20,12 @@
// clang-format off
template<std::input_or_output_iterator I>
requires std::indirectly_readable<I>
[[nodiscard]] constexpr bool check_subsumption() {
constexpr bool check_subsumption() {
return false;
}
template<std::input_iterator>
[[nodiscard]] constexpr bool check_subsumption() {
constexpr bool check_subsumption() {
return true;
}
// clang-format on

View File

@ -17,12 +17,12 @@
// clang-format off
template<std::weakly_incrementable>
[[nodiscard]] constexpr bool check_subsumption() {
constexpr bool check_subsumption() {
return false;
}
template<std::input_or_output_iterator>
[[nodiscard]] constexpr bool check_subsumption() {
constexpr bool check_subsumption() {
return true;
}
// clang-format on

View File

@ -20,7 +20,7 @@
#include "read_write.h"
template <class In>
[[nodiscard]] constexpr bool check_indirectly_readable() {
constexpr bool check_indirectly_readable() {
constexpr bool result = std::indirectly_readable<In>;
static_assert(std::indirectly_readable<In const> == result);
static_assert(std::indirectly_readable<In volatile> == result);

View File

@ -20,12 +20,12 @@
// clang-format off
template<std::input_or_output_iterator, std::semiregular>
[[nodiscard]] constexpr bool check_sentinel_subsumption() {
constexpr bool check_sentinel_subsumption() {
return false;
}
template<class I, std::sentinel_for<I> >
[[nodiscard]] constexpr bool check_subsumption() {
constexpr bool check_subsumption() {
return true;
}
// clang-format on

View File

@ -22,7 +22,7 @@
#include "read_write.h"
template <class Out, class T>
[[nodiscard]] constexpr bool check_indirectly_writable() {
constexpr bool check_indirectly_writable() {
constexpr bool result = std::indirectly_writable<Out, T>;
static_assert(std::indirectly_writable<Out const, T> == result);
return result;

View File

@ -32,10 +32,10 @@ public:
constexpr explicit iterator_wrapper(I i) noexcept : base_(std::move(i)) {}
// `noexcept(false)` is used to check that this operator is called.
[[nodiscard]] constexpr decltype(auto) operator*() const& noexcept(false) { return *base_; }
constexpr decltype(auto) operator*() const& noexcept(false) { return *base_; }
// `noexcept` is used to check that this operator is called.
[[nodiscard]] constexpr auto&& operator*() && noexcept { return std::move(*base_); }
constexpr auto&& operator*() && noexcept { return std::move(*base_); }
constexpr iterator_wrapper& operator++() noexcept {
++base_;
@ -44,7 +44,7 @@ public:
constexpr void operator++(int) noexcept { ++base_; }
[[nodiscard]] constexpr bool operator==(iterator_wrapper const& other) const noexcept { return base_ == other.base_; }
constexpr bool operator==(iterator_wrapper const& other) const noexcept { return base_ == other.base_; }
private:
I base_ = I{};

View File

@ -20,7 +20,7 @@ public:
constexpr explicit unqualified_lookup_wrapper(I i) noexcept : base_(std::move(i)) {}
[[nodiscard]] constexpr decltype(auto) operator*() const noexcept { return *base_; }
constexpr decltype(auto) operator*() const noexcept { return *base_; }
constexpr unqualified_lookup_wrapper& operator++() noexcept {
++base_;
@ -29,13 +29,13 @@ public:
constexpr void operator++(int) noexcept { ++base_; }
[[nodiscard]] constexpr bool operator==(unqualified_lookup_wrapper const& other) const noexcept {
constexpr bool operator==(unqualified_lookup_wrapper const& other) const noexcept {
return base_ == other.base_;
}
// Delegates `std::ranges::iter_move` for the underlying iterator. `noexcept(false)` will be used
// to ensure that the unqualified-lookup overload is chosen.
[[nodiscard]] friend constexpr decltype(auto) iter_move(unqualified_lookup_wrapper& i) noexcept(false) {
friend constexpr decltype(auto) iter_move(unqualified_lookup_wrapper& i) noexcept(false) {
return std::ranges::iter_move(i.base_);
}

View File

@ -26,13 +26,13 @@ struct range {
template<std::ranges::range R>
requires std::input_iterator<std::ranges::iterator_t<R>>
[[nodiscard]] constexpr bool check_input_range_subsumption() {
constexpr bool check_input_range_subsumption() {
return false;
}
template<std::ranges::input_range>
requires true
[[nodiscard]] constexpr bool check_input_range_subsumption() {
constexpr bool check_input_range_subsumption() {
return true;
}
@ -40,13 +40,13 @@ static_assert(check_input_range_subsumption<range>());
template<std::ranges::input_range R>
requires std::forward_iterator<std::ranges::iterator_t<R>>
[[nodiscard]] constexpr bool check_forward_range_subsumption() {
constexpr bool check_forward_range_subsumption() {
return false;
}
template<std::ranges::forward_range>
requires true
[[nodiscard]] constexpr bool check_forward_range_subsumption() {
constexpr bool check_forward_range_subsumption() {
return true;
}
@ -54,13 +54,13 @@ static_assert(check_forward_range_subsumption<range>());
template<std::ranges::forward_range R>
requires std::bidirectional_iterator<std::ranges::iterator_t<R>>
[[nodiscard]] constexpr bool check_bidirectional_range_subsumption() {
constexpr bool check_bidirectional_range_subsumption() {
return false;
}
template<std::ranges::bidirectional_range>
requires true
[[nodiscard]] constexpr bool check_bidirectional_range_subsumption() {
constexpr bool check_bidirectional_range_subsumption() {
return true;
}

View File

@ -261,62 +261,62 @@ struct totally_ordered_with_others {
};
struct no_lt_not_totally_ordered_with {
[[nodiscard]] bool operator==(no_lt_not_totally_ordered_with const&) const = default;
[[nodiscard]] auto operator<=>(no_lt_not_totally_ordered_with const&) const = default;
bool operator==(no_lt_not_totally_ordered_with const&) const = default;
auto operator<=>(no_lt_not_totally_ordered_with const&) const = default;
operator totally_ordered_with_others() const noexcept;
[[nodiscard]] bool operator==(totally_ordered_with_others const&) const;
[[nodiscard]] auto operator<=>(totally_ordered_with_others const&) const;
[[nodiscard]] auto operator<(totally_ordered_with_others const&) const;
bool operator==(totally_ordered_with_others const&) const;
auto operator<=>(totally_ordered_with_others const&) const;
auto operator<(totally_ordered_with_others const&) const;
};
struct no_gt_not_totally_ordered_with {
[[nodiscard]] bool operator==(no_gt_not_totally_ordered_with const&) const = default;
[[nodiscard]] auto operator<=>(no_gt_not_totally_ordered_with const&) const = default;
bool operator==(no_gt_not_totally_ordered_with const&) const = default;
auto operator<=>(no_gt_not_totally_ordered_with const&) const = default;
operator totally_ordered_with_others() const noexcept;
[[nodiscard]] bool operator==(totally_ordered_with_others const&) const;
[[nodiscard]] auto operator<=>(totally_ordered_with_others const&) const;
[[nodiscard]] auto operator>(totally_ordered_with_others const&) const;
bool operator==(totally_ordered_with_others const&) const;
auto operator<=>(totally_ordered_with_others const&) const;
auto operator>(totally_ordered_with_others const&) const;
};
struct no_le_not_totally_ordered_with {
[[nodiscard]] bool operator==(no_le_not_totally_ordered_with const&) const = default;
[[nodiscard]] auto operator<=>(no_le_not_totally_ordered_with const&) const = default;
bool operator==(no_le_not_totally_ordered_with const&) const = default;
auto operator<=>(no_le_not_totally_ordered_with const&) const = default;
operator totally_ordered_with_others() const noexcept;
[[nodiscard]] bool operator==(totally_ordered_with_others const&) const;
[[nodiscard]] auto operator<=>(totally_ordered_with_others const&) const;
[[nodiscard]] auto operator<=(totally_ordered_with_others const&) const;
bool operator==(totally_ordered_with_others const&) const;
auto operator<=>(totally_ordered_with_others const&) const;
auto operator<=(totally_ordered_with_others const&) const;
};
struct no_ge_not_totally_ordered_with {
[[nodiscard]] bool operator==(no_ge_not_totally_ordered_with const&) const = default;
[[nodiscard]] auto operator<=>(no_ge_not_totally_ordered_with const&) const = default;
bool operator==(no_ge_not_totally_ordered_with const&) const = default;
auto operator<=>(no_ge_not_totally_ordered_with const&) const = default;
operator totally_ordered_with_others() const noexcept;
[[nodiscard]] bool operator==(totally_ordered_with_others const&) const;
[[nodiscard]] auto operator<=>(totally_ordered_with_others const&) const;
[[nodiscard]] auto operator>=(totally_ordered_with_others const&) const;
bool operator==(totally_ordered_with_others const&) const;
auto operator<=>(totally_ordered_with_others const&) const;
auto operator>=(totally_ordered_with_others const&) const;
};
struct partial_ordering_totally_ordered_with {
[[nodiscard]] auto operator<=>(partial_ordering_totally_ordered_with const&) const noexcept = default;
[[nodiscard]] std::partial_ordering operator<=>(totally_ordered_with_others const&) const noexcept;
auto operator<=>(partial_ordering_totally_ordered_with const&) const noexcept = default;
std::partial_ordering operator<=>(totally_ordered_with_others const&) const noexcept;
operator totally_ordered_with_others() const;
};
struct weak_ordering_totally_ordered_with {
[[nodiscard]] auto operator<=>(weak_ordering_totally_ordered_with const&) const noexcept = default;
[[nodiscard]] std::weak_ordering operator<=>(totally_ordered_with_others const&) const noexcept;
auto operator<=>(weak_ordering_totally_ordered_with const&) const noexcept = default;
std::weak_ordering operator<=>(totally_ordered_with_others const&) const noexcept;
operator totally_ordered_with_others() const;
};
struct strong_ordering_totally_ordered_with {
[[nodiscard]] auto operator<=>(strong_ordering_totally_ordered_with const&) const noexcept = default;
[[nodiscard]] std::strong_ordering operator<=>(totally_ordered_with_others const&) const noexcept;
auto operator<=>(strong_ordering_totally_ordered_with const&) const noexcept = default;
std::strong_ordering operator<=>(totally_ordered_with_others const&) const noexcept;
operator totally_ordered_with_others() const;
};

View File

@ -730,9 +730,9 @@ public:
constexpr explicit stride_counting_iterator(I current) : base_(std::move(current)) {}
[[nodiscard]] constexpr I const& base() const& { return base_; }
constexpr I const& base() const& { return base_; }
[[nodiscard]] constexpr I base() && { return std::move(base_); }
constexpr I base() && { return std::move(base_); }
constexpr difference_type stride_count() const { return stride_count_; }