diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv --- a/libcxx/docs/Status/Cxx2bIssues.csv +++ b/libcxx/docs/Status/Cxx2bIssues.csv @@ -91,7 +91,7 @@ `3544 `__,"``format-arg-store::args`` is unintentionally not exposition-only","June 2021","","","|format|" `3546 `__,"``common_iterator``'s postfix-proxy is not quite right","June 2021","","","|ranges|" `3548 `__,"``shared_ptr`` construction from ``unique_ptr`` should move (not copy) the deleter","June 2021","","" -`3549 `__,"``view_interface`` is overspecified to derive from ``view_base``","June 2021","","","|ranges|" +`3549 `__,"``view_interface`` is overspecified to derive from ``view_base``","June 2021","|Complete|","14.0","|ranges|" `3551 `__,"``borrowed_{iterator,subrange}_t`` are overspecified","June 2021","","","|ranges|" `3552 `__,"Parallel specialized memory algorithms should require forward iterators","June 2021","","" `3553 `__,"Useless constraint in ``split_view::outer-iterator::value_type::begin()``","June 2021","","","|ranges|" diff --git a/libcxx/include/__ranges/enable_view.h b/libcxx/include/__ranges/enable_view.h --- a/libcxx/include/__ranges/enable_view.h +++ b/libcxx/include/__ranges/enable_view.h @@ -12,6 +12,7 @@ #include <__config> #include +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -25,8 +26,17 @@ struct view_base { }; +template + requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>> +class view_interface; + +template + requires is_convertible_v<_Op*, view_interface<_Yp>*> +void __is_derived_from_view_interface(const _Op*, const view_interface<_Yp>*); + template -inline constexpr bool enable_view = derived_from<_Tp, view_base>; +inline constexpr bool enable_view = derived_from<_Tp, view_base> || + requires { ranges::__is_derived_from_view_interface((_Tp*)nullptr, (_Tp*)nullptr); }; } // end namespace ranges diff --git a/libcxx/include/__ranges/view_interface.h b/libcxx/include/__ranges/view_interface.h --- a/libcxx/include/__ranges/view_interface.h +++ b/libcxx/include/__ranges/view_interface.h @@ -18,7 +18,6 @@ #include <__ranges/access.h> #include <__ranges/concepts.h> #include <__ranges/empty.h> -#include <__ranges/enable_view.h> #include #include @@ -40,7 +39,7 @@ template requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>> -class view_interface : public view_base { +class view_interface { _LIBCPP_HIDE_FROM_ABI constexpr _Derived& __derived() noexcept { static_assert(sizeof(_Derived) && derived_from<_Derived, view_interface> && view<_Derived>); diff --git a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp --- a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp +++ b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp @@ -79,6 +79,11 @@ }; static_assert(std::ranges::view); +struct MI : std::ranges::view_interface, + std::ranges::view_interface { +}; +static_assert(!std::ranges::view); + struct EmptyIsTrue : std::ranges::view_interface { int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; constexpr ForwardIter begin() const { return ForwardIter(const_cast(buff)); } @@ -300,6 +305,10 @@ return true; } +struct V1 : std::ranges::view_interface { }; +struct V2 : std::ranges::view_interface { V1 base_; }; +static_assert(sizeof(V2) == sizeof(V1)); + int main(int, char**) { testEmpty(); static_assert(testEmpty());