C++ Logo

std-discussion

Advanced search

Re: Metaprogramming with the range-based "for" loop.

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Thu, 9 Dec 2021 20:24:12 -0500
On Thu, Dec 9, 2021 at 12:31 PM Andrew Schepler via Std-Discussion
<std-discussion_at_[hidden]> wrote:
>
> I recently wanted a way to determine whether or not an expression can appear to the right of ":" in the range-based for syntax, and what the type of the element (*__begin) is if so.

Why do you specifically need to know if it can appear in a range-based
`for` loop?

The C++20 concept `std::ranges::range<T>` detects whether `T` is a
range. Anything which is a C++20 range can be used in a range-based
`for` loop. Now the reverse is not true: many types which are not
C++20 ranges can work in range-based `for`.

But why would you want to allow "technically valid" code to work?

Also, `std::ranges::iterator_t<Range>` results in the iterator type
for the range. This is what `std::ranges::begin()` returns. But this
requires that `Range` is a C++20 range type.

Your code in C++20 would be written as:

```
namespace ranges = std::ranges

class Thing {...};

class ThingCollection
{
public:
  template<std::convertible_to<Thing> T>
  void add(T &&);

  template<ranges::range Rng>
    requires std::convertible_to<ranges::value_t<Rng>, Thing>
  void add(Rng &&rng)
  {
    for(auto &&elem: rng)
    {
      add(std::forward<decltype(elem)>(elem));
    }
  }

};
```

> Still, would it maybe be worth a standard proposal to provide a truly correct way to do this, plus make it easier than all that code imitating what a compiler needs to do internally anyway?

No. We don't want people to write code with such simplistic semantics.
Ranges should be *ranges*, not just things with begin/end on them.

Received on 2021-12-09 19:24:26