[PATCH] libstdc++: Implement P3137R3 views::to_input for C++26

Patrick Palka ppalka@redhat.com
Tue Mar 11 16:54:15 GMT 2025


On Tue, 11 Mar 2025, Tomasz Kaminski wrote:

> 
> 
> On Tue, Mar 11, 2025 at 5:04 PM Patrick Palka <ppalka@redhat.com> wrote:
>       On Tue, 11 Mar 2025, Tomasz Kaminski wrote:
> 
>       >
>       >
>       > On Mon, Mar 10, 2025 at 11:28 PM Patrick Palka <ppalka@redhat.com> wrote:
>       >       Tested on x86_64-pc-linux-gnu, does this look OK for trunk?
>       >
>       >       -- >8 --
>       >
>       >       libstdc++-v3/ChangeLog:
>       >
>       >               * include/bits/version.def (ranges_to_input): Define.
>       >               * include/bits/version.h: Regenerate.
>       >               * include/std/ranges (ranges::to_input_view): Define for C++26.
>       >               (views::__detail::__can_to_input): Likewise.
>       >               (views::_ToInput, views::to_input): Likewise.
>       >               * testsuite/std/ranges/adaptors/to_input/1.cc: New test.
>       >       ---
>       >        libstdc++-v3/include/bits/version.def         |   8 +
>       >        libstdc++-v3/include/bits/version.h           |  10 ++
>       >        libstdc++-v3/include/std/ranges               | 170 ++++++++++++++++++
>       >        .../std/ranges/adaptors/to_input/1.cc         |  58 ++++++
>       >        4 files changed, 246 insertions(+)
>       >        create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/to_input/1.cc
>       >
>       >       diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
>       >       index 2af5a54bff2..c2b5283df89 100644
>       >       --- a/libstdc++-v3/include/bits/version.def
>       >       +++ b/libstdc++-v3/include/bits/version.def
>       >       @@ -1910,6 +1910,14 @@ ftms = {
>       >          };
>       >        };
>       >
>       >       +ftms = {
>       >       +  name = ranges_to_input;
>       >       +  values = {
>       >       +    v = 202502;
>       >       +    cxxmin = 26;
>       >       +  };
>       >       +};
>       >       +
>       >        ftms = {
>       >          name = to_string;
>       >          values = {
>       >       diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
>       >       index 9833023cfdc..775c8642139 100644
>       >       --- a/libstdc++-v3/include/bits/version.h
>       >       +++ b/libstdc++-v3/include/bits/version.h
>       >       @@ -2120,6 +2120,16 @@
>       >        #endif /* !defined(__cpp_lib_text_encoding) && defined(__glibcxx_want_text_encoding) */
>       >        #undef __glibcxx_want_text_encoding
>       >
>       >       +#if !defined(__cpp_lib_ranges_to_input)
>       >       +# if (__cplusplus >  202302L)
>       >       +#  define __glibcxx_ranges_to_input 202502L
>       >       +#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_to_input)
>       >       +#   define __cpp_lib_ranges_to_input 202502L
>       >       +#  endif
>       >       +# endif
>       >       +#endif /* !defined(__cpp_lib_ranges_to_input) && defined(__glibcxx_want_ranges_to_input) */
>       >       +#undef __glibcxx_want_ranges_to_input
>       >       +
>       >        #if !defined(__cpp_lib_to_string)
>       >        # if (__cplusplus >  202302L) && _GLIBCXX_HOSTED && (__glibcxx_to_chars)
>       >        #  define __glibcxx_to_string 202306L
>       >       diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
>       >       index e21f5284b46..dd97d276ef0 100644
>       >       --- a/libstdc++-v3/include/std/ranges
>       >       +++ b/libstdc++-v3/include/std/ranges
>       >       @@ -69,6 +69,7 @@
>       >        #define __glibcxx_want_ranges_slide
>       >        #define __glibcxx_want_ranges_stride
>       >        #define __glibcxx_want_ranges_to_container
>       >       +#define __glibcxx_want_ranges_to_input
>       >        #define __glibcxx_want_ranges_zip
>       >        #include <bits/version.h>
>       >
>       >       @@ -10390,6 +10391,175 @@ namespace ranges
>       >        } // namespace ranges
>       >        #endif // __cpp_lib_ranges_cache_latest
>       >
>       >       +#if __cpp_lib_ranges_to_input // C++ >= 26
>       >       +namespace ranges
>       >       +{
>       >       +  template<input_range _Vp>
>       >       +    requires view<_Vp>
>       >       +  class to_input_view : public view_interface<to_input_view<_Vp>>
>       >       +  {
>       >       +    _Vp _M_base = _Vp();
>       >       +
>       >       +    template<bool _Const>
>       >       +    class _Iterator;
>       >       +
>       >       +  public:
>       >       +    to_input_view() requires default_initializable<_Vp> = default;
>       >       +
>       >       +    constexpr explicit
>       >       +    to_input_view(_Vp __base)
>       >       +    : _M_base(std::move(__base))
>       >       +    { }
>       >       +
>       >       +    constexpr _Vp
>       >       +    base() const & requires copy_constructible<_Vp>
>       >       +    { return _M_base; }
>       >       +
>       >       +    constexpr _Vp
>       >       +    base() &&
>       >       +    { return std::move(_M_base); }
>       >       +
>       >       +    constexpr auto
>       >       +    begin() requires (!__detail::__simple_view<_Vp>)
>       >       +    { return _Iterator<false>(ranges::begin(_M_base)); }
>       >       +
>       >       +    constexpr auto
>       >       +    begin() const requires range<const _Vp>
>       >       +    { return _Iterator<true>(ranges::begin(_M_base)); }
>       >       +
>       >       +    constexpr auto
>       >       +    end() requires (!__detail::__simple_view<_Vp>)
>       >       +    { return ranges::end(_M_base); }
>       >       +
>       >       +    constexpr auto
>       >       +    end() const requires range<const _Vp>
>       >       +    { return ranges::end(_M_base); }
>       >       +
>       >       +    constexpr auto
>       >       +    size() requires sized_range<_Vp>
>       >       +    { return ranges::size(_M_base); }
>       >       +
>       >       +    constexpr auto
>       >       +    size() const requires sized_range<const _Vp>
>       >       +    { return ranges::size(_M_base); }
>       >       +  };
>       >       +
>       >       +  template<typename _Range>
>       >       +    to_input_view(_Range&&) -> to_input_view<views::all_t<_Range>>;
>       >       +
>       >       +  template<input_range _Vp>
>       >       +    requires view<_Vp>
>       >       +  template<bool _Const>
>       >       +  class to_input_view<_Vp>::_Iterator
>       >       +  {
>       >       +    using _Base = __maybe_const_t<_Const, _Vp>;
>       >       +
>       >       +    iterator_t<_Base> _M_current = iterator_t<_Base>();
>       >       +
>       >       +    constexpr explicit
>       >       +    _Iterator(iterator_t<_Base> __current)
>       >       +    : _M_current(std::move(__current))
>       >       +    { }
>       >       +
>       >       +    friend to_input_view;
>       >       +    friend _Iterator<!_Const>;
>       >       +
>       >       +  public:
>       >       +    using difference_type = range_difference_t<_Base>;
>       >       +    using value_type = range_value_t<_Base>;
>       >       +    using iterator_concept = input_iterator_tag;
>       >       +
>       >       +    _Iterator() requires default_initializable<iterator_t<_Base>> = default;
>       >       +
>       >       +    _Iterator(_Iterator&&) = default;
>       >       +    _Iterator& operator=(_Iterator&&) = default;
>       >       +
>       >       +    constexpr
>       >       +    _Iterator(_Iterator<!_Const> __i)
>       >       +      requires _Const && convertible_to<iterator_t<_Vp>, iterator_t<_Base>>
>       >       +    : _M_current(std::move(__i._M_current))
>       >       +    { }
>       >       +
>       >       +    constexpr iterator_t<_Base>
>       >       +    base() &&
>       >       +    { return std::move(_M_current); }
>       >       +
>       >       +    constexpr const iterator_t<_Base>&
>       >       +    base() const & noexcept
>       >       +    { return _M_current; }
>       >       +
>       >       +    constexpr decltype(auto)
>       >       +    operator*() const
>       >       +    { return *_M_current; }
>       >       +
>       >       +    constexpr _Iterator&
>       >       +    operator++()
>       >       +    {
>       >       +      ++_M_current;
>       >       +      return *this;
>       >       +    }
>       >       +
>       >       +    constexpr void
>       >       +    operator++(int)
>       >       +    { ++*this; }
>       >       +
>       >       +    friend constexpr bool
>       >       +    operator==(const _Iterator& __x, const sentinel_t<_Base>& __y)
>       >       +    { return __x._M_current == __y; }
>       >       +
>       >       +    friend constexpr difference_type
>       >       +    operator-(const sentinel_t<_Base>& __y, const _Iterator& __x)
>       >       +      requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
>       >       +    { return __y - __x._M_current; }
>       >       +
>       >       +    friend constexpr difference_type
>       >       +    operator-(const _Iterator& __x, const sentinel_t<_Base>& __y)
>       >       +      requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
>       >       +    { return __x._M_current - __y; }
>       >       +
>       >       +    friend constexpr range_rvalue_reference_t<_Base>
>       >       +    iter_move(const _Iterator& __i)
>       >       +      noexcept(noexcept(ranges::iter_move(__i._M_current)))
>       >       +    { return ranges::iter_move(__i._M_current); }
>       >       +
>       >       +    friend constexpr void
>       >       +    iter_swap(const _Iterator& __x, const _Iterator& __y)
>       >       +      noexcept(noexcept(ranges::iter_swap(__x._M_current, __y._M_current)))
>       >       +      requires indirectly_swappable<iterator_t<_Base>>
>       >       +    { ranges::iter_swap(__x._M_current, __y._M_current); }
>       >       +  };
>       >       +
>       >       +  namespace views
>       >       +  {
>       >       +    namespace __detail
>       >       +    {
>       >       +      template<typename _Tp>
>       >       +       concept __can_to_input = requires { to_input_view(std::declval<_Tp>()); };
>       >       +    }
>       >       +
>       >       +    struct _ToInput : __adaptor::_RangeAdaptorClosure<_ToInput>
>       >       +    {
>       >       +      template<viewable_range _Range>
>       >       +       requires __detail::__can_to_input<_Range>
>       >       +       constexpr auto
>       >       +       operator() [[nodiscard]] (_Range&& __r) const
>       >       +       {
>       >       +         if constexpr (input_range<_Range>
>       >       +                       && !common_range<_Range>
>       >       +                       && !forward_range<_Range>)
>       >       +           return views::all(__r);
>       >       +         else
>       >       +           return to_input_view(std::forward<_Range>(__r));
>       >       +       }
>       >       +
>       >       +      static constexpr bool _S_has_simple_call_op = true;
>       >       +    };
>       >       +
>       >       +    inline constexpr _ToInput to_input;
>       >       +  }
>       >       +} // namespace ranges
>       >       +#endif // __cpp_lib_ranges_to_input
>       >       +
>       >        _GLIBCXX_END_NAMESPACE_VERSION
>       >        } // namespace std
>       >        #endif // library concepts
>       >       diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/to_input/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/to_input/1.cc
>       >       new file mode 100644
>       >       index 00000000000..1e43281adb4
>       >       --- /dev/null
>       >       +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/to_input/1.cc
>       >       @@ -0,0 +1,58 @@
>       >       +// { dg-do run { target c++26 } }
>       >       +
>       >       +#include <ranges>
>       >       +
>       >       +#if __cpp_lib_ranges_to_input != 202502L
>       >       +# error "Feature-test macro __cpp_lib_ranges_to_input has wrong value in <ranges>"
>       >       +#endif
>       >       +
>       >       +#include <algorithm>
>       >       +#include <vector>
>       >       +#include <testsuite_hooks.h>
>       >       +#include <testsuite_iterators.h>
>       >       +
>       >       +namespace ranges = std::ranges;
>       >       +namespace views = std::views;
>       >       +
>       >       +void
>       >       +test01()
>       >       +{
>       >       +  std::vector<int> r{1,2,3};
>       >       +  auto v = r | views::to_input;
>       >       +  using type = decltype(v);
>       >       +  static_assert( ranges::input_range<type> && !ranges::forward_range<type> );
>       >       +
>       >       +  VERIFY( ranges::equal(v.base(), r) );
>       >       +  VERIFY( v.size() == r.size() );
>       >       +  VERIFY( v.end() == r.end() );
>       >       +  auto it = v.begin();
>       >       +  VERIFY( it != r.end() );
>       >       +  *it = 42;
>       >       +  ++it;
>       >       +  *it = 43;
>       >       +  it++;
>       >       +  ranges::iter_swap(v.begin(), it);
>       >
>       > As far as I can tell this is not invoking the iter_swap friend function, and instead defaulting to swap by 3 iter_moves.
>       > We cannot copy the iterator, but you could replace v.begin(), with views::to_input(v).begin() to call the overload, and
>       > have the same effect.
> 
>       v is the to_input_view, not the vector, so both arguments are
>       to_input_view iterators and I'd expect the friend function gets
>       used here?  Looks like it is, demonstrated by a static_assert(false)
>       added to its body:
> 
> Indeed, I got confused by the name (v being for vector), and the friend overload is called.

The range adaptor tests tend to use 'v' as the name of the adapted view
FWIW.

> We are also calling begin on input_range twice, which is not guaranteed to work in general,
> but seem to be well-defined in this case.

Hmm good point -- while the to_input_view iterator is always move-only,
it's not always single pass, the latter property is inherited from the
underlying range.

Here's an updated patch that uses std::same_as in the testcase, and
slightly extends the testcase to verify views::to_input is idempotent.
I also added a missing forward in the views::all branch of to_input.

-- >8 --

libstdc++-v3/ChangeLog:

	* include/bits/version.def (ranges_to_input): Define.
	* include/bits/version.h: Regenerate.
	* include/std/ranges (ranges::to_input_view): Define for C++26.
	(views::__detail::__can_to_input): Likewise.
	(views::_ToInput, views::to_input): Likewise.
	* testsuite/std/ranges/adaptors/to_input/1.cc: New test.
---
 libstdc++-v3/include/bits/version.def         |   8 +
 libstdc++-v3/include/bits/version.h           |  10 ++
 libstdc++-v3/include/std/ranges               | 170 ++++++++++++++++++
 .../std/ranges/adaptors/to_input/1.cc         |  59 ++++++
 4 files changed, 247 insertions(+)
 create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/to_input/1.cc

diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 2af5a54bff2..c2b5283df89 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1910,6 +1910,14 @@ ftms = {
   };
 };
 
+ftms = {
+  name = ranges_to_input;
+  values = {
+    v = 202502;
+    cxxmin = 26;
+  };
+};
+
 ftms = {
   name = to_string;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index 9833023cfdc..775c8642139 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2120,6 +2120,16 @@
 #endif /* !defined(__cpp_lib_text_encoding) && defined(__glibcxx_want_text_encoding) */
 #undef __glibcxx_want_text_encoding
 
+#if !defined(__cpp_lib_ranges_to_input)
+# if (__cplusplus >  202302L)
+#  define __glibcxx_ranges_to_input 202502L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_to_input)
+#   define __cpp_lib_ranges_to_input 202502L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_ranges_to_input) && defined(__glibcxx_want_ranges_to_input) */
+#undef __glibcxx_want_ranges_to_input
+
 #if !defined(__cpp_lib_to_string)
 # if (__cplusplus >  202302L) && _GLIBCXX_HOSTED && (__glibcxx_to_chars)
 #  define __glibcxx_to_string 202306L
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index e21f5284b46..c2a2d6f4e05 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -69,6 +69,7 @@
 #define __glibcxx_want_ranges_slide
 #define __glibcxx_want_ranges_stride
 #define __glibcxx_want_ranges_to_container
+#define __glibcxx_want_ranges_to_input
 #define __glibcxx_want_ranges_zip
 #include <bits/version.h>
 
@@ -10390,6 +10391,175 @@ namespace ranges
 } // namespace ranges
 #endif // __cpp_lib_ranges_cache_latest
 
+#if __cpp_lib_ranges_to_input // C++ >= 26
+namespace ranges
+{
+  template<input_range _Vp>
+    requires view<_Vp>
+  class to_input_view : public view_interface<to_input_view<_Vp>>
+  {
+    _Vp _M_base = _Vp();
+
+    template<bool _Const>
+    class _Iterator;
+
+  public:
+    to_input_view() requires default_initializable<_Vp> = default;
+
+    constexpr explicit
+    to_input_view(_Vp __base)
+    : _M_base(std::move(__base))
+    { }
+
+    constexpr _Vp
+    base() const & requires copy_constructible<_Vp>
+    { return _M_base; }
+
+    constexpr _Vp
+    base() &&
+    { return std::move(_M_base); }
+
+    constexpr auto
+    begin() requires (!__detail::__simple_view<_Vp>)
+    { return _Iterator<false>(ranges::begin(_M_base)); }
+
+    constexpr auto
+    begin() const requires range<const _Vp>
+    { return _Iterator<true>(ranges::begin(_M_base)); }
+
+    constexpr auto
+    end() requires (!__detail::__simple_view<_Vp>)
+    { return ranges::end(_M_base); }
+
+    constexpr auto
+    end() const requires range<const _Vp>
+    { return ranges::end(_M_base); }
+
+    constexpr auto
+    size() requires sized_range<_Vp>
+    { return ranges::size(_M_base); }
+
+    constexpr auto
+    size() const requires sized_range<const _Vp>
+    { return ranges::size(_M_base); }
+  };
+
+  template<typename _Range>
+    to_input_view(_Range&&) -> to_input_view<views::all_t<_Range>>;
+
+  template<input_range _Vp>
+    requires view<_Vp>
+  template<bool _Const>
+  class to_input_view<_Vp>::_Iterator
+  {
+    using _Base = __maybe_const_t<_Const, _Vp>;
+
+    iterator_t<_Base> _M_current = iterator_t<_Base>();
+
+    constexpr explicit
+    _Iterator(iterator_t<_Base> __current)
+    : _M_current(std::move(__current))
+    { }
+
+    friend to_input_view;
+    friend _Iterator<!_Const>;
+
+  public:
+    using difference_type = range_difference_t<_Base>;
+    using value_type = range_value_t<_Base>;
+    using iterator_concept = input_iterator_tag;
+
+    _Iterator() requires default_initializable<iterator_t<_Base>> = default;
+
+    _Iterator(_Iterator&&) = default;
+    _Iterator& operator=(_Iterator&&) = default;
+
+    constexpr
+    _Iterator(_Iterator<!_Const> __i)
+      requires _Const && convertible_to<iterator_t<_Vp>, iterator_t<_Base>>
+    : _M_current(std::move(__i._M_current))
+    { }
+
+    constexpr iterator_t<_Base>
+    base() &&
+    { return std::move(_M_current); }
+
+    constexpr const iterator_t<_Base>&
+    base() const & noexcept
+    { return _M_current; }
+
+    constexpr decltype(auto)
+    operator*() const
+    { return *_M_current; }
+
+    constexpr _Iterator&
+    operator++()
+    {
+      ++_M_current;
+      return *this;
+    }
+
+    constexpr void
+    operator++(int)
+    { ++*this; }
+
+    friend constexpr bool
+    operator==(const _Iterator& __x, const sentinel_t<_Base>& __y)
+    { return __x._M_current == __y; }
+
+    friend constexpr difference_type
+    operator-(const sentinel_t<_Base>& __y, const _Iterator& __x)
+      requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
+    { return __y - __x._M_current; }
+
+    friend constexpr difference_type
+    operator-(const _Iterator& __x, const sentinel_t<_Base>& __y)
+      requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
+    { return __x._M_current - __y; }
+
+    friend constexpr range_rvalue_reference_t<_Base>
+    iter_move(const _Iterator& __i)
+      noexcept(noexcept(ranges::iter_move(__i._M_current)))
+    { return ranges::iter_move(__i._M_current); }
+
+    friend constexpr void
+    iter_swap(const _Iterator& __x, const _Iterator& __y)
+      noexcept(noexcept(ranges::iter_swap(__x._M_current, __y._M_current)))
+      requires indirectly_swappable<iterator_t<_Base>>
+    { ranges::iter_swap(__x._M_current, __y._M_current); }
+  };
+
+  namespace views
+  {
+    namespace __detail
+    {
+      template<typename _Tp>
+	concept __can_to_input = requires { to_input_view(std::declval<_Tp>()); };
+    }
+
+    struct _ToInput : __adaptor::_RangeAdaptorClosure<_ToInput>
+    {
+      template<viewable_range _Range>
+	requires __detail::__can_to_input<_Range>
+	constexpr auto
+	operator() [[nodiscard]] (_Range&& __r) const
+	{
+	  if constexpr (input_range<_Range>
+			&& !common_range<_Range>
+			&& !forward_range<_Range>)
+	    return views::all(std::forward<_Range>(__r));
+	  else
+	    return to_input_view(std::forward<_Range>(__r));
+	}
+
+      static constexpr bool _S_has_simple_call_op = true;
+    };
+
+    inline constexpr _ToInput to_input;
+  }
+} // namespace ranges
+#endif // __cpp_lib_ranges_to_input
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // library concepts
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/to_input/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/to_input/1.cc
new file mode 100644
index 00000000000..cde368a2f64
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/to_input/1.cc
@@ -0,0 +1,59 @@
+// { dg-do run { target c++26 } }
+
+#include <ranges>
+
+#if __cpp_lib_ranges_to_input != 202502L
+# error "Feature-test macro __cpp_lib_ranges_to_input has wrong value in <ranges>"
+#endif
+
+#include <algorithm>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+namespace ranges = std::ranges;
+namespace views = std::views;
+
+void
+test01()
+{
+  std::vector<int> r{1,2,3};
+  auto v = r | views::to_input;
+  using type = decltype(v);
+  static_assert( ranges::input_range<type> && !ranges::forward_range<type> );
+
+  VERIFY( ranges::equal(v.base(), r) );
+  VERIFY( v.size() == r.size() );
+  VERIFY( v.end() == r.end() );
+  auto it = v.begin();
+  VERIFY( it != r.end() );
+  *it = 42;
+  ++it;
+  *it = 43;
+  it++;
+  ranges::iter_swap(v.begin(), it);
+  VERIFY( ranges::equal(r, (int[]){3,43,42}) );
+  *it = ranges::iter_move(it);
+  VERIFY( it == r.begin() + 2 );
+  VERIFY( r.end() - it == 1 );
+  VERIFY( it - r.end() == -1 );
+}
+
+void
+test02()
+{
+  int x[] = {1,2,3};
+  __gnu_test::test_input_range<int> rx(x);
+  static_assert( !ranges::common_range<decltype(rx)> );
+  auto v = rx | views::to_input;
+  static_assert( std::same_as<decltype(v), decltype(views::all(rx))> );
+  static_assert( std::same_as<decltype(x | views::to_input),
+			      decltype(x | views::to_input | views::to_input)> );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
-- 
2.49.0.rc1.37.ge969bc8759

> 
>       In file included from src/libstdc++-v3/testsuite/std/ranges/adaptors/to_input/1.cc:3:
>       /scratchpad/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/ranges: In instantiation of ‘constexpr void std::ranges::iter_swap(const to_input_view<ref_view<std::__debug::vector<int> >
>       >::_Iterator<true>&, const to_input_view<ref_view<std::__debug::vector<int> > >::_Iterator<true>&) requires  indirectly_swappable<decltype(std::ranges::__access::__begin((declval<typename
>       std::__conditional<_Const>::type<const _Vp, _Vp>&>)())), decltype(std::ranges::__access::__begin((declval<typename std::__conditional<_Const>::type<const _Vp, _Vp>&>)()))>’:
>       /scratchpad/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/iterator_concepts.h:949:15:   required from ‘constexpr void std::ranges::__iswap::_IterSwap::operator()(_Tp&&, _Up&&) const
>       [with _Tp = std::ranges::to_input_view<std::ranges::ref_view<std::__debug::vector<int> > >::_Iterator<true>; _Up = std::ranges::to_input_view<std::ranges::ref_view<std::__debug::vector<int> >
>       >::_Iterator<true>&]’
>         949 |             iter_swap(static_cast<_Tp&&>(__e1), static_cast<_Up&&>(__e2));
>             |             ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>       src/libstdc++-v3/testsuite/std/ranges/adaptors/to_input/1.cc:34:20:   required from here
>          34 |   ranges::iter_swap(v.begin(), it);
>             |   ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
>       /scratchpad/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/ranges:10529:21: error: static assertion failed
>       10529 |     { static_assert(false); ranges::iter_swap(__x._M_current, __y._M_current); }
>             |                     ^~~~~
>       /scratchpad/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/ranges:10529:21: note: ‘false’ evaluates to false
> 
>       >       +  VERIFY( ranges::equal(r, (int[]){3,43,42}) );
>       >       +  *it = ranges::iter_move(it);
>       >       +  VERIFY( it == r.begin() + 2 );
>       >       +  VERIFY( r.end() - it == 1 );
>       >       +  VERIFY( it - r.end() == -1 );
>       >       +}
>       >       +
>       >       +void
>       >       +test02()
>       >       +{
>       >       +  int x[] = {1,2,3};
>       >       +  __gnu_test::test_input_range<int> rx(x);
>       >       +  static_assert( !ranges::common_range<decltype(rx)> );
>       >       +  auto v = rx | views::to_input;
>       >       +  using type = decltype(v);
>       >       +  using type = ranges::ref_view<decltype(rx)>;
>       >
>       > I would prefer a more direct representation of this check, as static_assert(std::is_same_v<decltype(views::all(rx)), decltype())>);
> 
>       Sounds good.  The 'using' technique doesn't add much here since the type
>       names are short and we don't subsequently use the alias anywhere.
> 
>       >       +}
>       >       +
>       >       +int
>       >       +main()
>       >       +{
>       >       +  test01();
>       >       +  test02();
>       >       +}
>       >       --
>       >       2.49.0.rc1.37.ge969bc8759
>       >
>       >
>       >
> 
> 
> 


More information about the Libstdc++ mailing list