Date: Fri, 10 Dec 2021 13:21:27 -0400
This works in Clang...
template<class...T>struct Over:T...,std::true_type{};
template<class...T> Over(T...) -> Over<T...>;
template <typename T>
concept rangeforable = Over{[]{for(auto&&x:T{})(void)x;}};
static_assert( ! rangeforable<int> );
static_assert( rangeforable<int[2]> );
static_assert( rangeforable<std::initializer_list<int>> );
On Thu, Dec 9, 2021 at 9:24 PM Jason McKesson via Std-Discussion <
std-discussion_at_[hidden]> wrote:
> 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.
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>
template<class...T>struct Over:T...,std::true_type{};
template<class...T> Over(T...) -> Over<T...>;
template <typename T>
concept rangeforable = Over{[]{for(auto&&x:T{})(void)x;}};
static_assert( ! rangeforable<int> );
static_assert( rangeforable<int[2]> );
static_assert( rangeforable<std::initializer_list<int>> );
On Thu, Dec 9, 2021 at 9:24 PM Jason McKesson via Std-Discussion <
std-discussion_at_[hidden]> wrote:
> 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.
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>
Received on 2021-12-10 11:21:42