In the upcoming C++20 ranges there will be the range concept with the following definition:
template< class T >
concept range = __RangeImpl<T&>; // exposition-only definition
template< class T >
concept __RangeImpl = requires(T&& t) {
ranges::begin(std::forward<T>(t)); // equality-preserving for forward iterators
ranges::end (std::forward<T>(t));
};
template< class T >
concept __ForwardingRange = ranges::range<T> && __RangeImpl<T>;
Translating this to plain English I'd say that the only requirement for a type to satisfy the range concept is to be callable with ranges::begin and ranges::end.
However if I create an empty type with just begin and end a static assertion on the range concept fails?
namespace ranges = std::experimental::ranges;
struct A {
void begin() {}
void end() {}
};
static_assert(ranges::range<A>);
What am I missing?
Per [range.access.begin]: (emphasis mine)
The name
ranges::begin
denotes a customization point object. The expressionranges::begin(E)
for some subexpressionE
is expression-equivalent to:
[...]
Otherwise, if
E
is an lvalue,decay-copy(E.begin())
if it is a valid expression and its typeI
modelsinput_or_output_iterator
.[...]
With your A
, A.begin()
is of type void
, which can't possibly be an iterator. Therefore, ranges::begin(std::declval<A>())
is invalid.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With