Skip to content

Commit 06e7769

Browse files
Implement LWG-3715: view_interface::empty is overconstrained (#2946)
Co-authored-by: Stephan T. Lavavej <[email protected]>
1 parent 374fc90 commit 06e7769

File tree

7 files changed

+48
-35
lines changed

7 files changed

+48
-35
lines changed

stl/inc/xutility

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2722,24 +2722,32 @@ namespace ranges {
27222722
public:
27232723
#ifdef __clang__ // TRANSITION, LLVM-44833
27242724
template <class _Dx = _Derived>
2725-
_NODISCARD constexpr bool empty() requires forward_range<_Dx>
2725+
_NODISCARD constexpr bool empty() requires sized_range<_Dx> || forward_range<_Dx>
27262726
#else // ^^^ workaround / no workaround vvv
2727-
_NODISCARD constexpr bool empty() requires forward_range<_Derived>
2727+
_NODISCARD constexpr bool empty() requires sized_range<_Derived> || forward_range<_Derived>
27282728
#endif // TRANSITION, LLVM-44833
27292729
{
27302730
auto& _Self = _Cast();
2731-
return _RANGES begin(_Self) == _RANGES end(_Self);
2731+
if constexpr (sized_range<_Derived>) {
2732+
return _RANGES size(_Self) == 0;
2733+
} else {
2734+
return _RANGES begin(_Self) == _RANGES end(_Self);
2735+
}
27322736
}
27332737

27342738
#ifdef __clang__ // TRANSITION, LLVM-44833
27352739
template <class _Dx = _Derived>
2736-
_NODISCARD constexpr bool empty() const requires forward_range<const _Dx>
2740+
_NODISCARD constexpr bool empty() const requires sized_range<const _Dx> || forward_range<const _Dx>
27372741
#else // ^^^ workaround / no workaround vvv
2738-
_NODISCARD constexpr bool empty() const requires forward_range<const _Derived>
2742+
_NODISCARD constexpr bool empty() const requires sized_range<const _Derived> || forward_range<const _Derived>
27392743
#endif // TRANSITION, LLVM-44833
27402744
{
27412745
auto& _Self = _Cast();
2742-
return _RANGES begin(_Self) == _RANGES end(_Self);
2746+
if constexpr (sized_range<const _Derived>) {
2747+
return _RANGES size(_Self) == 0;
2748+
} else {
2749+
return _RANGES begin(_Self) == _RANGES end(_Self);
2750+
}
27432751
}
27442752

27452753
#ifdef __clang__ // TRANSITION, LLVM-44833

tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ namespace test_view_interface {
8383

8484
S end();
8585
S end() const requires (to_bool(HasConstRange));
86+
87+
unsigned int size() requires (to_bool(Diff) && !std::derived_from<Cat, forward_iterator_tag>);
88+
unsigned int size() const requires (to_bool(HasConstRange) && to_bool(Diff)
89+
&& !std::derived_from<Cat, forward_iterator_tag>);
8690
};
8791
// clang-format on
8892

@@ -133,13 +137,13 @@ namespace test_view_interface {
133137
STATIC_ASSERT(ranges::range<V>);
134138
STATIC_ASSERT(!ranges::range<V const>);
135139
STATIC_ASSERT(ranges::view<V>);
136-
STATIC_ASSERT(!CanEmpty<V&>);
140+
STATIC_ASSERT(CanEmpty<V&>);
137141
STATIC_ASSERT(!CanEmpty<V const&>);
138-
STATIC_ASSERT(!CanBool<V&>);
142+
STATIC_ASSERT(CanBool<V&>);
139143
STATIC_ASSERT(!CanBool<V const&>);
140144
STATIC_ASSERT(!CanData<V&>);
141145
STATIC_ASSERT(!CanData<V const&>);
142-
STATIC_ASSERT(!CanSize<V&>);
146+
STATIC_ASSERT(CanSize<V&>);
143147
STATIC_ASSERT(!CanSize<V const&>);
144148
STATIC_ASSERT(!CanMemberFront<V&>);
145149
STATIC_ASSERT(!CanMemberFront<V const&>);
@@ -154,14 +158,14 @@ namespace test_view_interface {
154158
STATIC_ASSERT(ranges::range<V>);
155159
STATIC_ASSERT(ranges::range<V const>);
156160
STATIC_ASSERT(ranges::view<V>);
157-
STATIC_ASSERT(!CanEmpty<V&>);
158-
STATIC_ASSERT(!CanEmpty<V const&>);
159-
STATIC_ASSERT(!CanBool<V&>);
160-
STATIC_ASSERT(!CanBool<V const&>);
161+
STATIC_ASSERT(CanEmpty<V&>);
162+
STATIC_ASSERT(CanEmpty<V const&>);
163+
STATIC_ASSERT(CanBool<V&>);
164+
STATIC_ASSERT(CanBool<V const&>);
161165
STATIC_ASSERT(!CanData<V&>);
162166
STATIC_ASSERT(!CanData<V const&>);
163-
STATIC_ASSERT(!CanSize<V&>);
164-
STATIC_ASSERT(!CanSize<V const&>);
167+
STATIC_ASSERT(CanSize<V&>);
168+
STATIC_ASSERT(CanSize<V const&>);
165169
STATIC_ASSERT(!CanMemberFront<V&>);
166170
STATIC_ASSERT(!CanMemberFront<V const&>);
167171
STATIC_ASSERT(!CanMemberBack<V&>);
@@ -217,13 +221,13 @@ namespace test_view_interface {
217221
STATIC_ASSERT(ranges::range<V>);
218222
STATIC_ASSERT(!ranges::range<V const>);
219223
STATIC_ASSERT(ranges::view<V>);
220-
STATIC_ASSERT(!CanEmpty<V&>);
224+
STATIC_ASSERT(CanEmpty<V&>);
221225
STATIC_ASSERT(!CanEmpty<V const&>);
222-
STATIC_ASSERT(!CanBool<V&>);
226+
STATIC_ASSERT(CanBool<V&>);
223227
STATIC_ASSERT(!CanBool<V const&>);
224228
STATIC_ASSERT(!CanData<V&>);
225229
STATIC_ASSERT(!CanData<V const&>);
226-
STATIC_ASSERT(!CanSize<V&>);
230+
STATIC_ASSERT(CanSize<V&>);
227231
STATIC_ASSERT(!CanSize<V const&>);
228232
STATIC_ASSERT(!CanMemberFront<V&>);
229233
STATIC_ASSERT(!CanMemberFront<V const&>);
@@ -238,14 +242,14 @@ namespace test_view_interface {
238242
STATIC_ASSERT(ranges::range<V>);
239243
STATIC_ASSERT(ranges::range<V const>);
240244
STATIC_ASSERT(ranges::view<V>);
241-
STATIC_ASSERT(!CanEmpty<V&>);
242-
STATIC_ASSERT(!CanEmpty<V const&>);
243-
STATIC_ASSERT(!CanBool<V&>);
244-
STATIC_ASSERT(!CanBool<V const&>);
245+
STATIC_ASSERT(CanEmpty<V&>);
246+
STATIC_ASSERT(CanEmpty<V const&>);
247+
STATIC_ASSERT(CanBool<V&>);
248+
STATIC_ASSERT(CanBool<V const&>);
245249
STATIC_ASSERT(!CanData<V&>);
246250
STATIC_ASSERT(!CanData<V const&>);
247-
STATIC_ASSERT(!CanSize<V&>);
248-
STATIC_ASSERT(!CanSize<V const&>);
251+
STATIC_ASSERT(CanSize<V&>);
252+
STATIC_ASSERT(CanSize<V const&>);
249253
STATIC_ASSERT(!CanMemberFront<V&>);
250254
STATIC_ASSERT(!CanMemberFront<V const&>);
251255
STATIC_ASSERT(!CanMemberBack<V&>);

tests/std/tests/P0896R4_views_drop/test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
219219
}
220220

221221
// Validate view_interface::empty and operator bool
222-
STATIC_ASSERT(CanMemberEmpty<R> == forward_range<Rng>);
222+
STATIC_ASSERT(CanMemberEmpty<R> == (sized_range<Rng> || forward_range<Rng>) );
223223
STATIC_ASSERT(CanBool<R> == CanEmpty<R>);
224224
if constexpr (CanMemberEmpty<R>) {
225225
assert(r.empty() == is_empty);

tests/std/tests/P0896R4_views_elements/test.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ template <ranges::input_range Rng>
3636
constexpr bool test_one(Rng&& rng) {
3737
using ranges::elements_view, ranges::bidirectional_range, ranges::common_range, ranges::contiguous_range,
3838
ranges::enable_borrowed_range, ranges::forward_range, ranges::input_range, ranges::iterator_t, ranges::prev,
39-
ranges::random_access_range, ranges::range, ranges::range_reference_t, ranges::sentinel_t,
39+
ranges::random_access_range, ranges::range, ranges::range_reference_t, ranges::sentinel_t, ranges::sized_range,
4040
ranges::borrowed_range;
4141

4242
using V = views::all_t<Rng>;
@@ -157,7 +157,7 @@ constexpr bool test_one(Rng&& rng) {
157157
const bool is_empty = ranges::empty(expected_keys);
158158

159159
// Validate view_interface::empty and operator bool
160-
STATIC_ASSERT(CanMemberEmpty<R> == forward_range<Rng>);
160+
STATIC_ASSERT(CanMemberEmpty<R> == (sized_range<Rng> || forward_range<Rng>) );
161161
STATIC_ASSERT(CanBool<R> == CanEmpty<R>);
162162
if constexpr (CanMemberEmpty<R>) {
163163
assert(r.empty() == is_empty);
@@ -170,7 +170,7 @@ constexpr bool test_one(Rng&& rng) {
170170
}
171171
}
172172

173-
STATIC_ASSERT(CanMemberEmpty<const R> == forward_range<const Rng>);
173+
STATIC_ASSERT(CanMemberEmpty<const R> == (sized_range<const Rng> || forward_range<const Rng>) );
174174
STATIC_ASSERT(CanBool<const R> == CanEmpty<const R>);
175175
if constexpr (CanMemberEmpty<const R>) {
176176
assert(as_const(r).empty() == is_empty);

tests/std/tests/P0896R4_views_take/test.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
219219
}
220220

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

235-
STATIC_ASSERT(CanMemberEmpty<const R> == forward_range<const Rng>);
235+
STATIC_ASSERT(CanMemberEmpty<const R> == (sized_range<const Rng> || forward_range<const Rng>) );
236236
STATIC_ASSERT(CanBool<const R> == CanEmpty<const R>);
237237
if constexpr (CanMemberEmpty<const R>) {
238238
assert(as_const(r).empty() == is_empty);

tests/std/tests/P0896R4_views_transform/test.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ template <ranges::input_range Rng, ranges::random_access_range Expected>
4242
constexpr bool test_one(Rng&& rng, Expected&& expected) {
4343
using ranges::transform_view, ranges::bidirectional_range, ranges::common_range, ranges::contiguous_range,
4444
ranges::enable_borrowed_range, ranges::forward_range, ranges::input_range, ranges::iterator_t, ranges::prev,
45-
ranges::random_access_range, ranges::range, ranges::range_reference_t, ranges::sentinel_t;
45+
ranges::random_access_range, ranges::sized_range, ranges::range, ranges::range_reference_t, ranges::sentinel_t;
4646

4747
constexpr bool is_view = ranges::view<remove_cvref_t<Rng>>;
4848

@@ -169,7 +169,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
169169
constexpr bool const_invocable = regular_invocable<const Fun&, range_reference_t<const V>>;
170170

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

185-
STATIC_ASSERT(CanMemberEmpty<const R> == (forward_range<const Rng> && const_invocable));
185+
STATIC_ASSERT(CanMemberEmpty<const R> == ((sized_range<const Rng> || forward_range<const Rng>) &&const_invocable));
186186
STATIC_ASSERT(CanBool<const R> == CanEmpty<const R>);
187187
if constexpr (CanMemberEmpty<const R>) {
188188
assert(as_const(r).empty() == is_empty);

tests/std/tests/P2442R1_views_chunk/test.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ constexpr bool test_one(Rng&& rng, Expected&& expected) {
119119
}
120120

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

135-
STATIC_ASSERT(CanMemberEmpty<const R> == forward_range<const Rng>);
135+
STATIC_ASSERT(
136+
CanMemberEmpty<const R> == ((forward_range<Rng> && sized_range<const V>) || forward_range<const Rng>) );
136137
STATIC_ASSERT(CanBool<const R> == CanEmpty<const R>);
137138
if constexpr (CanMemberEmpty<const R>) {
138139
assert(as_const(r).empty() == is_empty);

0 commit comments

Comments
 (0)