Skip to content

Commit d4d409e

Browse files
authored
LWG-3549 view_interface is overspecified to derive from view_base (#2198)
1 parent eb70080 commit d4d409e

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed

stl/inc/xutility

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2681,8 +2681,21 @@ namespace ranges {
26812681

26822682
struct view_base {};
26832683

2684+
template <template <class...> class _Template, class... _Args>
2685+
void _Derived_from_specialization_impl(const _Template<_Args...>&);
2686+
2687+
template <class _Ty, template <class...> class _Template>
2688+
concept _Derived_from_specialization_of = requires(const _Ty& _Obj) {
2689+
_Derived_from_specialization_impl<_Template>(_Obj);
2690+
};
2691+
2692+
template <class _Derived>
2693+
requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
2694+
class view_interface;
2695+
26842696
template <class _Ty>
2685-
inline constexpr bool enable_view = derived_from<_Ty, view_base>;
2697+
inline constexpr bool enable_view =
2698+
derived_from<_Ty, view_base> || _Derived_from_specialization_of<_Ty, view_interface>;
26862699

26872700
#ifdef __cpp_lib_ranges // TRANSITION, GH-1814
26882701
template <class _Ty>
@@ -3016,7 +3029,7 @@ namespace ranges {
30163029
// clang-format off
30173030
template <class _Derived>
30183031
requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
3019-
class view_interface : public view_base {
3032+
class view_interface {
30203033
private:
30213034
_NODISCARD constexpr _Derived& _Cast() noexcept {
30223035
static_assert(derived_from<_Derived, view_interface>,

tests/std/tests/P0896R4_ranges_range_machinery/test.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1578,6 +1578,7 @@ using immutable_badsized_range = badsized_range<immutable_sized_range>;
15781578
template <class T>
15791579
constexpr bool ranges::disable_sized_range<badsized_range<T>> = true;
15801580

1581+
// "strange" in that const-ness affects the iterator type
15811582
struct strange_view {
15821583
strange_view() = default;
15831584
strange_view(strange_view&&) = default;
@@ -1591,7 +1592,15 @@ struct strange_view {
15911592
};
15921593

15931594
struct strange_view2 : strange_view, ranges::view_base {};
1594-
struct strange_view3 : strange_view2 {};
1595+
struct strange_view3 : strange_view2 {}; // not truly a view since enable_view<strange_view3> is false (see below)
1596+
struct strange_view4 : strange_view, ranges::view_interface<strange_view4> {};
1597+
struct strange_view5 : strange_view4, ranges::view_interface<strange_view5> {
1598+
// not truly a view since enable_view<strange_view5> is false due to multiple inheritance from view_interface
1599+
};
1600+
1601+
// Verify that specializations of view_interface do not inherit from view_base
1602+
STATIC_ASSERT(!std::is_base_of_v<std::ranges::view_base, ranges::view_interface<strange_view4>>);
1603+
STATIC_ASSERT(!std::is_base_of_v<std::ranges::view_base, ranges::view_interface<strange_view5>>);
15951604

15961605
template <>
15971606
inline constexpr bool ranges::enable_view<strange_view> = true;
@@ -1620,6 +1629,7 @@ namespace exhaustive_size_and_view_test {
16201629

16211630
using I = int*;
16221631
using CI = int const*;
1632+
using D = std::ptrdiff_t;
16231633
using S = std::size_t;
16241634
using UC = unsigned char;
16251635

@@ -1682,6 +1692,23 @@ namespace exhaustive_size_and_view_test {
16821692
STATIC_ASSERT(test<strange_view3&, false, I, S>());
16831693
STATIC_ASSERT(test<strange_view3 const, false, CI, S>());
16841694
STATIC_ASSERT(test<strange_view3 const&, false, CI, S>());
1695+
1696+
STATIC_ASSERT(test<strange_view4, true, I, D>());
1697+
STATIC_ASSERT(test<strange_view4&, false, I, D>());
1698+
STATIC_ASSERT(test<strange_view4 const, false, CI, D>());
1699+
STATIC_ASSERT(test<strange_view4 const&, false, CI, D>());
1700+
1701+
template <class = void>
1702+
constexpr bool strict_test_case() {
1703+
if constexpr (!is_permissive) {
1704+
STATIC_ASSERT(test<strange_view5, false, I, S>());
1705+
}
1706+
return true;
1707+
}
1708+
STATIC_ASSERT(strict_test_case());
1709+
STATIC_ASSERT(test<strange_view5&, false, I, S>());
1710+
STATIC_ASSERT(test<strange_view5 const, false, CI, S>());
1711+
STATIC_ASSERT(test<strange_view5 const&, false, CI, S>());
16851712
} // namespace exhaustive_size_and_view_test
16861713

16871714
// Validate output_range

0 commit comments

Comments
 (0)