@@ -1072,6 +1072,21 @@ namespace views
{
namespace __adaptor
{
+ template<typename _Tp>
+ inline constexpr auto
+ __maybe_refwrap(_Tp& __arg)
+ { return reference_wrapper<_Tp>{__arg}; }
+
+ template<typename _Tp>
+ inline constexpr auto
+ __maybe_refwrap(const _Tp& __arg)
+ { return reference_wrapper<const _Tp>{__arg}; }
+
+ template<typename _Tp>
+ inline constexpr decltype(auto)
+ __maybe_refwrap(_Tp&& __arg)
+ { return std::forward<_Tp>(__arg); }
+
template<typename _Callable>
struct _RangeAdaptorClosure;
@@ -1100,18 +1115,47 @@ namespace views
constexpr auto
operator()(_Args&&... __args) const
{
+ // [range.adaptor.object]: If a range adaptor object accepts more
+ // than one argument, then the following expressions are equivalent:
+ //
+ // (1) adaptor(range, args...)
+ // (2) adaptor(args...)(range)
+ // (3) range | adaptor(args...)
+ //
+ // In this case, adaptor(args...) is a range adaptor closure object.
+ //
+ // We handle (1) and (2) here, and (3) is just a special case of a
+ // more general case already handled by _RangeAdaptorClosure.
if constexpr (is_invocable_v<_Callable, _Args...>)
{
static_assert(sizeof...(_Args) != 1,
"a _RangeAdaptor that accepts only one argument "
"should be defined as a _RangeAdaptorClosure");
+ // Here we handle adaptor(range, args...) -- just forward all
+ // arguments to the underlying adaptor routine.
return _Callable{}(std::forward<_Args>(__args)...);
}
else
{
- auto __closure = [__args...] <typename _Range> (_Range&& __r) {
- return _Callable{}(std::forward<_Range>(__r), __args...);
- };
+ // Here we handle adaptor(args...)(range).
+ // Given args..., we return a _RangeAdaptorClosure that takes a
+ // range argument, such that (2) is equivalent to (1).
+ //
+ // We need to be careful about how we capture args... in this
+ // closure. By using __maybe_refwrap, we capture lvalue
+ // references by reference (through a reference_wrapper) and
+ // otherwise capture by value.
+ auto __closure
+ = [...__args(__maybe_refwrap(std::forward<_Args>(__args)))]
+ <typename _Range> (_Range&& __r) {
+ // This static_cast has two purposes: it forwards a
+ // reference_wrapper<T> capture as a T&, and otherwise
+ // forwards the captured argument as an rvalue.
+ return _Callable{}(std::forward<_Range>(__r),
+ (static_cast<unwrap_reference_t
+ <remove_const_t<decltype(__args)>>>
+ (__args))...);
+ };
using _ClosureType = decltype(__closure);
return _RangeAdaptorClosure<_ClosureType>(std::move(__closure));
}
@@ -74,10 +74,28 @@ test03()
VERIFY( i == v.end() );
}
+void
+test04()
+{
+ auto x = "the quick brown fox"sv;
+ std::initializer_list<char> p = {' ', ' '};
+ static_assert(!ranges::view<decltype(p)>);
+ static_assert(std::same_as<decltype(p | views::all),
+ ranges::ref_view<decltype(p)>>);
+ auto v = x | views::split(p);
+ auto i = v.begin();
+ VERIFY( ranges::equal(*i++, "the"sv) );
+ VERIFY( ranges::equal(*i++, "quick"sv) );
+ VERIFY( ranges::equal(*i++, "brown"sv) );
+ VERIFY( ranges::equal(*i++, "fox"sv) );
+ VERIFY( i == v.end() );
+}
+
int
main()
{
test01();
test02();
test03();
+ test04();
}
new file mode 100644
@@ -0,0 +1,51 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <algorithm>
+#include <ranges>
+#include <string_view>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+namespace ranges = std::ranges;
+namespace views = std::ranges::views;
+
+void
+test01()
+{
+ using namespace std::literals;
+ auto x = "the quick brown fox"sv;
+ auto v = views::split(x, std::initializer_list<char>{' ', ' '});
+ v.begin(); // { dg-error "" }
+}
+
+void
+test02()
+{
+ using namespace std::literals;
+ auto x = "the quick brown fox"sv;
+ auto v = x | views::split(std::initializer_list<char>{' ', ' '}); // { dg-error "no match" }
+ v.begin();
+}
+
+// { dg-prune-output "in requirements" }
+// { dg-error "deduction failed" "" { target *-*-* } 0 }
+// { dg-error "no match" "" { target *-*-* } 0 }
+// { dg-error "constraint failure" "" { target *-*-* } 0 }