Vinci
Vinci

Reputation: 1520

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?

Upvotes: 6

Views: 515

Answers (1)

L. F.
L. F.

Reputation: 20579

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.

Upvotes: 5

Related Questions