Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Satisfy std::ranges::range concept

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?

like image 498
Vinci Avatar asked Sep 27 '19 07:09

Vinci


1 Answers

Per [range.access.begin]: (emphasis mine)

The name ranges​::​begin denotes a customization point object. The expression ranges​::​​begin(E) for some subexpression E is expression-equivalent to:

  • [...]

  • Otherwise, if E is an lvalue, decay-copy(E.begin()) if it is a valid expression and its type I models input_­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.

like image 97
L. F. Avatar answered Nov 15 '22 08:11

L. F.