From 62b66f4ec42d4cb1670bd97ad4d5085e3b9c5500 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Kr=C3=BCgler?=
+Currently, projected is a wrapper of the implementation type regardless of whether Proj is identity.
+
+#include <algorithm>
+#include <ranges>
+#include <iostream>
+
+int main() {
+ auto outer = std::views::iota(0, 5)
+ | std::views::transform([](int i) {
+ return std::views::single(i) | std::views::filter([](int) { return true; });
+ });
+
+ for (auto&& inner : outer)
+ for (auto&& elem : inner)
+ std::cout << elem << " "; // 0 1 2 3 4
+
+ std::ranges::for_each(
+ outer,
+ [](auto&& inner) {
+ // error: passing 'const filter_view' as 'this' argument discards qualifiers
+ for (auto&& elem : inner)
+ std::cout << elem << " ";
+ });
+}
+
++In the above example, ranges::for_each requires indirect_unary_predicate<Pred, projected<I, identity>> +which ultimately requires invocable<Pred&, iter_common_reference_t<projected<I, identity>>>. +
+According to the current wording, the reference and value type of projected<I, identity> are filter_view&& +and filter_view& respectively, which causes its common reference to be eventually calculated as +const filter_view&. Since the former is not const-iterable, this results in a hard error during +instantiation because const begin is called unexpectedly in an unconstrained lambda. + ++It seems like having projected<I, identity> just be I is a more appropriate choice, +which makes the concept checking really specific to I rather than a potentially incomplete iterator wrapper. +
+ + +
+This wording is relative to
Modify
++ + ++-1- Class template projected is used to constrain algorithms that accept callable objects and projections +(
+). It combines an indirectly_readable type I and a callable +object type Proj into a new indirectly_readable type whose reference type is the +result of applying Proj to the iter_reference_t of I. + ++namespace std { + template<class I, class Proj> + struct projected-impl { // exposition only + struct type { // exposition only + using value_type = remove_cvref_t<indirect_result_t<Proj&, I>>; + using difference_type = iter_difference_t<I>; // present only if I + // models weakly_incrementable + indirect_result_t<Proj&, I> operator*() const; // not defined + }; + }; + + template<indirectly_readable I, indirectly_regular_unary_invocable<I> Proj> + using projected = conditional_t<is_same_v<Proj, identity>, I, typename projected-impl<I, Proj>::type>; +} +