//
// The optional static data member _Derived::_S_has_simple_extra_args should
// be defined to true if the behavior of this adaptor is independent of the
- // constness/value category of the extra arguments.
+ // constness/value category of the extra arguments. This data member could
+ // also be defined as a variable template parameterized by the types of the
+ // extra arguments.
template<typename _Derived>
struct _RangeAdaptor
{
concept __closure_has_simple_call_op = _Adaptor::_S_has_simple_call_op;
// True if the behavior of the range adaptor non-closure _Adaptor is
- // independent of the value category of its extra arguments.
- template<typename _Adaptor>
- concept __adaptor_has_simple_extra_args = _Adaptor::_S_has_simple_extra_args;
+ // independent of the value category of its extra arguments _Args.
+ template<typename _Adaptor, typename... _Args>
+ concept __adaptor_has_simple_extra_args = _Adaptor::_S_has_simple_extra_args
+ || _Adaptor::template _S_has_simple_extra_args<_Args...>;
// A range adaptor closure that represents partial application of
// the range adaptor _Adaptor with arguments _Args.
// This lets us get away with a single operator() overload, which makes
// overload resolution failure diagnostics more concise.
template<typename _Adaptor, typename... _Args>
- requires __adaptor_has_simple_extra_args<_Adaptor>
+ requires __adaptor_has_simple_extra_args<_Adaptor, _Args...>
struct _Partial<_Adaptor, _Args...> : _RangeAdaptorClosure
{
tuple<_Args...> _M_args;
// A lightweight specialization of the above template for the common case
// where _Adaptor accepts a single extra argument.
template<typename _Adaptor, typename _Arg>
- requires __adaptor_has_simple_extra_args<_Adaptor>
+ requires __adaptor_has_simple_extra_args<_Adaptor, _Arg>
struct _Partial<_Adaptor, _Arg> : _RangeAdaptorClosure
{
_Arg _M_arg;
using _RangeAdaptor<_Take>::operator();
static constexpr int _S_arity = 2;
- static constexpr bool _S_has_simple_extra_args = true;
+ // The count argument of views::take is not always simple -- it can be
+ // e.g. a move-only class that's implicitly convertible to the difference
+ // type. But an integer-like count argument is surely simple.
+ template<typename _Tp>
+ static constexpr bool _S_has_simple_extra_args
+ = ranges::__detail::__is_integer_like<_Tp>;
};
inline constexpr _Take take;
using _RangeAdaptor<_Drop>::operator();
static constexpr int _S_arity = 2;
- static constexpr bool _S_has_simple_extra_args = true;
+ template<typename _Tp>
+ static constexpr bool _S_has_simple_extra_args
+ = _Take::_S_has_simple_extra_args<_Tp>;
};
inline constexpr _Drop drop;
using _RangeAdaptor<_Split>::operator();
static constexpr int _S_arity = 2;
- // The second argument of views::split is _not_ simple -- it can be a
- // non-view range, the value category of which affects whether the call is
- // well-formed. So we must not define _S_has_simple_extra_args to true.
+ // The pattern argument of views::split is not always simple -- it can be
+ // a non-view range, the value category of which affects whether the call
+ // is well-formed. But a scalar or a view pattern argument is surely
+ // simple.
+ template<typename _Pattern>
+ static constexpr bool _S_has_simple_extra_args
+ = is_scalar_v<_Pattern> || (view<_Pattern>
+ && copy_constructible<_Pattern>);
};
inline constexpr _Split split;
void
test01()
{
- // Verify all multi-argument adaptors except for views::split are denoted
- // to have simple extra arguments.
+ // Verify adaptors are deemed to have simple extra arguments when appropriate.
using views::__adaptor::__adaptor_has_simple_extra_args;
- static_assert(__adaptor_has_simple_extra_args<decltype(views::transform)>);
- static_assert(__adaptor_has_simple_extra_args<decltype(views::filter)>);
- static_assert(__adaptor_has_simple_extra_args<decltype(views::drop)>);
- static_assert(__adaptor_has_simple_extra_args<decltype(views::take)>);
- static_assert(__adaptor_has_simple_extra_args<decltype(views::take_while)>);
- static_assert(__adaptor_has_simple_extra_args<decltype(views::drop_while)>);
- static_assert(!__adaptor_has_simple_extra_args<decltype(views::split)>);
+ using std::identity;
+ static_assert(__adaptor_has_simple_extra_args<decltype(views::transform), identity>);
+ static_assert(__adaptor_has_simple_extra_args<decltype(views::filter), identity>);
+ static_assert(__adaptor_has_simple_extra_args<decltype(views::drop), int>);
+ static_assert(__adaptor_has_simple_extra_args<decltype(views::take), int>);
+ static_assert(__adaptor_has_simple_extra_args<decltype(views::take_while), identity>);
+ static_assert(__adaptor_has_simple_extra_args<decltype(views::drop_while), identity>);
+ static_assert(__adaptor_has_simple_extra_args<decltype(views::split), std::string_view>);
+ static_assert(__adaptor_has_simple_extra_args<decltype(views::split), char>);
+ static_assert(!__adaptor_has_simple_extra_args<decltype(views::split), std::string>);
// Verify all adaptor closures except for views::split(pattern) have a simple
// operator().
__closure_has_simple_call_op auto a08 = views::common;
__closure_has_simple_call_op auto a09 = views::reverse;
__closure_has_simple_call_op auto a10 = views::keys;
+ __closure_has_simple_call_op auto a11 = views::split(' ');
// Verify composition of simple closures is simple.
__closure_has_simple_call_op auto b
- = (a00 | a01) | (a02 | a03) | (a04 | a05 | a06) | (a07 | a08 | a09 | a10);
+ = (a00 | a01) | (a02 | a03) | (a04 | a05 | a06) | (a07 | a08 | a09 | a10) | a11;
- // Verify views::split is the exception.
- auto a11 = views::split(' ');
- static_assert(!__closure_has_simple_call_op<decltype(a11)>);
- static_assert(!__closure_has_simple_call_op<decltype(a11 | a00)>);
- static_assert(!__closure_has_simple_call_op<decltype(a00 | a11)>);
+ // Verify views::split(non_view_range) is an exception.
+ extern std::string s;
+ auto a12 = views::split(s);
+ static_assert(!__closure_has_simple_call_op<decltype(a12)>);
+ static_assert(!__closure_has_simple_call_op<decltype(a12 | a00)>);
+ static_assert(!__closure_has_simple_call_op<decltype(a00 | a12)>);
}
void
// fallback deleted overload, so when a call is ill-formed overload resolution
// fails.
extern int x[10];
- auto badarg = nullptr;
+ struct { } badarg;
views::transform(badarg)(x); // { dg-error "no match" }
views::filter(badarg)(x); // { dg-error "no match" }
- views::take(badarg)(x); // { dg-error "no match" }
- views::drop(badarg)(x); // { dg-error "no match" }
views::take_while(badarg)(x); // { dg-error "no match" }
views::drop_while(badarg)(x); // { dg-error "no match" }
(views::transform(badarg) | views::all)(x); // { dg-error "no match" }
(views::filter(badarg) | views::all)(x); // { dg-error "no match" }
- (views::take(badarg) | views::all)(x); // { dg-error "no match" }
- (views::drop(badarg) | views::all)(x); // { dg-error "no match" }
(views::take_while(badarg) | views::all)(x); // { dg-error "no match" }
(views::drop_while(badarg) | views::all)(x); // { dg-error "no match" }
a0(x); // { dg-error "no match" };
auto a1 = a0 | views::all;
a1(x); // { dg-error "no match" }
+
+ views::take(badarg)(x); // { dg-error "deleted" }
+ views::drop(badarg)(x); // { dg-error "deleted" }
+ (views::take(badarg) | views::all)(x); // { dg-error "deleted" }
+ (views::drop(badarg) | views::all)(x); // { dg-error "deleted" }
+}
+
+void
+test03()
+{
+ // PR libstdc++/100940
+ extern int x[10];
+ struct S { operator int() && { return 5; }; };
+ x | std::views::take(S{});
+ x | std::views::drop(S{});
}
// { dg-prune-output "in requirements" }