Tested on x86_64-pc-linux-gnu, does this look OK for trunk?
-- >8 --
This patch proactively implements the proposed resolution for this LWG
issue, which seems straightforward and slated to be approved as-is.
I opted to not add a _GLIBCXX_RESOLVE_LIB_DEFECTS code comment for this
since concat_view is C++26 and hasn't been shipped in a GCC release yet.
libstdc++-v3/ChangeLog:
* include/std/ranges (concat_view::begin): Add space after
'requires' starting a requires-clause.
(concat_view::end): Refine condition for returning an iterator
rather than default_sentinel as per LWG 4166.
* testsuite/std/ranges/concat/1.cc (test03): Verify LWG 4166
example.
---
libstdc++-v3/include/std/ranges | 10 ++++----
libstdc++-v3/testsuite/std/ranges/concat/1.cc | 23 +++++++++++++++++++
2 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 5b455888536..a6c4d66520c 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -9687,7 +9687,7 @@ namespace ranges
{ }
constexpr iterator<false>
- begin() requires(!(__detail::__simple_view<_Vs> && ...))
+ begin() requires (!(__detail::__simple_view<_Vs> && ...))
{
iterator<false> __it(this, in_place_index<0>,
ranges::begin(std::get<0>(_M_views)));
__it.template _M_satisfy<0>();
@@ -9703,9 +9703,10 @@ namespace ranges
}
constexpr auto
- end() requires(!(__detail::__simple_view<_Vs> && ...))
+ end() requires (!(__detail::__simple_view<_Vs> && ...))
{
- if constexpr (__detail::__last_is_common<_Vs...>::value)
+ if constexpr ((semiregular<iterator_t<_Vs>> && ...)
+ && __detail::__last_is_common<_Vs...>::value)
{
constexpr auto __n = sizeof...(_Vs);
return iterator<false>(this, in_place_index<__n - 1>,
@@ -9718,7 +9719,8 @@ namespace ranges
constexpr auto
end() const requires (range<const _Vs> && ...) &&
__detail::__concatable<const _Vs...>
{
- if constexpr (__detail::__last_is_common<const _Vs...>::value)
+ if constexpr ((semiregular<iterator_t<const _Vs>> && ...)
+ && __detail::__last_is_common<const _Vs...>::value)
{
constexpr auto __n = sizeof...(_Vs);
return iterator<true>(this, in_place_index<__n - 1>,
diff --git a/libstdc++-v3/testsuite/std/ranges/concat/1.cc
b/libstdc++-v3/testsuite/std/ranges/concat/1.cc
index 6ffe28ece51..511a7e8a858 100644
--- a/libstdc++-v3/testsuite/std/ranges/concat/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/concat/1.cc
@@ -10,6 +10,7 @@
#include <algorithm>
#include <vector>
#include <array>
+#include <sstream>
#include <utility>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
@@ -66,9 +67,31 @@ test02()
VERIFY( ranges::equal(v | views::drop(1), x) );
}
+void
+test03()
+{
+ // LWG 4166 - concat_view::end() should be more constrained in order to
+ // support noncopyable iterators
+ auto range_copyable_it = std::vector<int>{1, 2, 3};
+
+ std::stringstream ss{"4 5 6"};
+ auto range_noncopyable_it = views::istream<int>(ss);
+
+ auto view1 = views::concat(range_copyable_it, range_noncopyable_it);
+ static_assert( ranges::range<decltype(view1)> );
+ VERIFY( ranges::equal(view1, std::vector{1, 2, 3, 4, 5, 6}) );
+
+ ss = std::stringstream{"4 5 6"};
+ range_noncopyable_it = views::istream<int>(ss);
+ auto view2 = views::concat(range_noncopyable_it, range_copyable_it);
+ static_assert( ranges::range<decltype(view2)> );
+ VERIFY( ranges::equal(view2, std::vector{4, 5, 6, 1, 2, 3}) );
+}
+
int
main()
{
static_assert(test01());
test02();
+ test03();
}
--
2.47.0.107.g34b6ce9b30