Implement LWG-3715: `view_interface::empty` is overconstrained (#2946)

Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
This commit is contained in:
A. Jiang 2022-07-28 11:53:00 +08:00 коммит произвёл GitHub
Родитель 374fc90b6c
Коммит 06e7769550
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 48 добавлений и 35 удалений

Просмотреть файл

@ -2722,24 +2722,32 @@ namespace ranges {
public:
#ifdef __clang__ // TRANSITION, LLVM-44833
template <class _Dx = _Derived>
_NODISCARD constexpr bool empty() requires forward_range<_Dx>
_NODISCARD constexpr bool empty() requires sized_range<_Dx> || forward_range<_Dx>
#else // ^^^ workaround / no workaround vvv
_NODISCARD constexpr bool empty() requires forward_range<_Derived>
_NODISCARD constexpr bool empty() requires sized_range<_Derived> || forward_range<_Derived>
#endif // TRANSITION, LLVM-44833
{
auto& _Self = _Cast();
return _RANGES begin(_Self) == _RANGES end(_Self);
if constexpr (sized_range<_Derived>) {
return _RANGES size(_Self) == 0;
} else {
return _RANGES begin(_Self) == _RANGES end(_Self);
}
}
#ifdef __clang__ // TRANSITION, LLVM-44833
template <class _Dx = _Derived>
_NODISCARD constexpr bool empty() const requires forward_range<const _Dx>
_NODISCARD constexpr bool empty() const requires sized_range<const _Dx> || forward_range<const _Dx>
#else // ^^^ workaround / no workaround vvv
_NODISCARD constexpr bool empty() const requires forward_range<const _Derived>
_NODISCARD constexpr bool empty() const requires sized_range<const _Derived> || forward_range<const _Derived>
#endif // TRANSITION, LLVM-44833
{
auto& _Self = _Cast();
return _RANGES begin(_Self) == _RANGES end(_Self);
if constexpr (sized_range<const _Derived>) {
return _RANGES size(_Self) == 0;
} else {
return _RANGES begin(_Self) == _RANGES end(_Self);
}
}
#ifdef __clang__ // TRANSITION, LLVM-44833

Просмотреть файл

@ -83,6 +83,10 @@ namespace test_view_interface {
S end();
S end() const requires (to_bool(HasConstRange));
unsigned int size() requires (to_bool(Diff) && !std::derived_from<Cat, forward_iterator_tag>);
unsigned int size() const requires (to_bool(HasConstRange) && to_bool(Diff)
&& !std::derived_from<Cat, forward_iterator_tag>);
};
// clang-format on
@ -133,13 +137,13 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::range<V>);
STATIC_ASSERT(!ranges::range<V const>);
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(!CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
STATIC_ASSERT(!CanBool<V&>);
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
STATIC_ASSERT(!CanData<V const&>);
STATIC_ASSERT(!CanSize<V&>);
STATIC_ASSERT(CanSize<V&>);
STATIC_ASSERT(!CanSize<V const&>);
STATIC_ASSERT(!CanMemberFront<V&>);
STATIC_ASSERT(!CanMemberFront<V const&>);
@ -154,14 +158,14 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::range<V>);
STATIC_ASSERT(ranges::range<V const>);
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(!CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
STATIC_ASSERT(!CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
STATIC_ASSERT(!CanData<V const&>);
STATIC_ASSERT(!CanSize<V&>);
STATIC_ASSERT(!CanSize<V const&>);
STATIC_ASSERT(CanSize<V&>);
STATIC_ASSERT(CanSize<V const&>);
STATIC_ASSERT(!CanMemberFront<V&>);
STATIC_ASSERT(!CanMemberFront<V const&>);
STATIC_ASSERT(!CanMemberBack<V&>);
@ -217,13 +221,13 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::range<V>);
STATIC_ASSERT(!ranges::range<V const>);
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(!CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
STATIC_ASSERT(!CanBool<V&>);
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
STATIC_ASSERT(!CanData<V const&>);
STATIC_ASSERT(!CanSize<V&>);
STATIC_ASSERT(CanSize<V&>);
STATIC_ASSERT(!CanSize<V const&>);
STATIC_ASSERT(!CanMemberFront<V&>);
STATIC_ASSERT(!CanMemberFront<V const&>);
@ -238,14 +242,14 @@ namespace test_view_interface {
STATIC_ASSERT(ranges::range<V>);
STATIC_ASSERT(ranges::range<V const>);
STATIC_ASSERT(ranges::view<V>);
STATIC_ASSERT(!CanEmpty<V&>);
STATIC_ASSERT(!CanEmpty<V const&>);
STATIC_ASSERT(!CanBool<V&>);
STATIC_ASSERT(!CanBool<V const&>);
STATIC_ASSERT(CanEmpty<V&>);
STATIC_ASSERT(CanEmpty<V const&>);
STATIC_ASSERT(CanBool<V&>);
STATIC_ASSERT(CanBool<V const&>);
STATIC_ASSERT(!CanData<V&>);
STATIC_ASSERT(!CanData<V const&>);
STATIC_ASSERT(!CanSize<V&>);
STATIC_ASSERT(!CanSize<V const&>);
STATIC_ASSERT(CanSize<V&>);
STATIC_ASSERT(CanSize<V const&>);
STATIC_ASSERT(!CanMemberFront<V&>);
STATIC_ASSERT(!CanMemberFront<V const&>);
STATIC_ASSERT(!CanMemberBack<V&>);

Просмотреть файл

@ -219,7 +219,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
}
// Validate view_interface::empty and operator bool
STATIC_ASSERT(CanMemberEmpty<R> == forward_range<Rng>);
STATIC_ASSERT(CanMemberEmpty<R> == (sized_range<Rng> || forward_range<Rng>) );
STATIC_ASSERT(CanBool<R> == CanEmpty<R>);
if constexpr (CanMemberEmpty<R>) {
assert(r.empty() == is_empty);

Просмотреть файл

@ -36,7 +36,7 @@ template <ranges::input_range Rng>
constexpr bool test_one(Rng&& rng) {
using ranges::elements_view, ranges::bidirectional_range, ranges::common_range, ranges::contiguous_range,
ranges::enable_borrowed_range, ranges::forward_range, ranges::input_range, ranges::iterator_t, ranges::prev,
ranges::random_access_range, ranges::range, ranges::range_reference_t, ranges::sentinel_t,
ranges::random_access_range, ranges::range, ranges::range_reference_t, ranges::sentinel_t, ranges::sized_range,
ranges::borrowed_range;
using V = views::all_t<Rng>;
@ -157,7 +157,7 @@ constexpr bool test_one(Rng&& rng) {
const bool is_empty = ranges::empty(expected_keys);
// Validate view_interface::empty and operator bool
STATIC_ASSERT(CanMemberEmpty<R> == forward_range<Rng>);
STATIC_ASSERT(CanMemberEmpty<R> == (sized_range<Rng> || forward_range<Rng>) );
STATIC_ASSERT(CanBool<R> == CanEmpty<R>);
if constexpr (CanMemberEmpty<R>) {
assert(r.empty() == is_empty);
@ -170,7 +170,7 @@ constexpr bool test_one(Rng&& rng) {
}
}
STATIC_ASSERT(CanMemberEmpty<const R> == forward_range<const Rng>);
STATIC_ASSERT(CanMemberEmpty<const R> == (sized_range<const Rng> || forward_range<const Rng>) );
STATIC_ASSERT(CanBool<const R> == CanEmpty<const R>);
if constexpr (CanMemberEmpty<const R>) {
assert(as_const(r).empty() == is_empty);

Просмотреть файл

@ -219,7 +219,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
}
// Validate view_interface::empty and operator bool
STATIC_ASSERT(CanMemberEmpty<R> == forward_range<Rng>);
STATIC_ASSERT(CanMemberEmpty<R> == (sized_range<Rng> || forward_range<Rng>) );
STATIC_ASSERT(CanBool<R> == CanEmpty<R>);
if constexpr (CanMemberEmpty<R>) {
assert(r.empty() == is_empty);
@ -232,7 +232,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
}
}
STATIC_ASSERT(CanMemberEmpty<const R> == forward_range<const Rng>);
STATIC_ASSERT(CanMemberEmpty<const R> == (sized_range<const Rng> || forward_range<const Rng>) );
STATIC_ASSERT(CanBool<const R> == CanEmpty<const R>);
if constexpr (CanMemberEmpty<const R>) {
assert(as_const(r).empty() == is_empty);

Просмотреть файл

@ -42,7 +42,7 @@ template <ranges::input_range Rng, ranges::random_access_range Expected>
constexpr bool test_one(Rng&& rng, Expected&& expected) {
using ranges::transform_view, ranges::bidirectional_range, ranges::common_range, ranges::contiguous_range,
ranges::enable_borrowed_range, ranges::forward_range, ranges::input_range, ranges::iterator_t, ranges::prev,
ranges::random_access_range, ranges::range, ranges::range_reference_t, ranges::sentinel_t;
ranges::random_access_range, ranges::sized_range, ranges::range, ranges::range_reference_t, ranges::sentinel_t;
constexpr bool is_view = ranges::view<remove_cvref_t<Rng>>;
@ -169,7 +169,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
constexpr bool const_invocable = regular_invocable<const Fun&, range_reference_t<const V>>;
// Validate view_interface::empty and operator bool
STATIC_ASSERT(CanMemberEmpty<R> == forward_range<Rng>);
STATIC_ASSERT(CanMemberEmpty<R> == (sized_range<Rng> || forward_range<Rng>) );
STATIC_ASSERT(CanBool<R> == CanEmpty<R>);
if constexpr (CanMemberEmpty<R>) {
assert(r.empty() == is_empty);
@ -182,7 +182,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
}
}
STATIC_ASSERT(CanMemberEmpty<const R> == (forward_range<const Rng> && const_invocable));
STATIC_ASSERT(CanMemberEmpty<const R> == ((sized_range<const Rng> || forward_range<const Rng>) &&const_invocable));
STATIC_ASSERT(CanBool<const R> == CanEmpty<const R>);
if constexpr (CanMemberEmpty<const R>) {
assert(as_const(r).empty() == is_empty);

Просмотреть файл

@ -119,7 +119,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
}
// Validate view_interface::empty and operator bool
STATIC_ASSERT(CanMemberEmpty<R> == forward_range<V>);
STATIC_ASSERT(CanMemberEmpty<R> == (sized_range<V> || forward_range<V>) );
STATIC_ASSERT(CanBool<R> == CanEmpty<R>);
if constexpr (CanMemberEmpty<R>) {
assert(r.empty() == is_empty);
@ -132,7 +132,8 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
}
}
STATIC_ASSERT(CanMemberEmpty<const R> == forward_range<const Rng>);
STATIC_ASSERT(
CanMemberEmpty<const R> == ((forward_range<Rng> && sized_range<const V>) || forward_range<const Rng>) );
STATIC_ASSERT(CanBool<const R> == CanEmpty<const R>);
if constexpr (CanMemberEmpty<const R>) {
assert(as_const(r).empty() == is_empty);