Skip to content

Commit

Permalink
New issue from Hewill Kang: "projected<I, identity> should just be I"
Browse files Browse the repository at this point in the history
  • Loading branch information
Dani-Hub committed Oct 14, 2023
1 parent 26534a1 commit 62b66f4
Showing 1 changed file with 99 additions and 0 deletions.
99 changes: 99 additions & 0 deletions xml/issue3996.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?xml version='1.0' encoding='utf-8' standalone='no'?>
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">

<issue num="3996" status="New">
<title><tt>projected&lt;I, identity&gt;</tt> should just be <tt>I</tt></title>
<section><sref ref="[projected]"/></section>
<submitter>Hewill Kang</submitter>
<date>12 Oct 2023</date>
<priority>99</priority>

<discussion>
<p>
Currently, <tt>projected</tt> is a wrapper of the implementation type regardless of whether <tt>Proj</tt> is <tt>identity</tt>.
<p/>
Since <tt>identity</tt> always returns a reference, this prevents <tt>projected&lt;I, identity&gt;</tt> from fully
emulating the properties of the original iterator when its reference is a prvalue.
<p/>
Such non-equivalence may lead to unexpected behavior in some cases (<a href="https://godbolt.org/z/KM45ndWvh">demo</a>):
</p>
<blockquote><pre>
#include &lt;algorithm&gt;
#include &lt;ranges&gt;
#include &lt;iostream&gt;

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&amp;&amp; inner : outer)
for (auto&amp;&amp; elem : inner)
std::cout &lt;&lt; elem &lt;&lt; " "; // 0 1 2 3 4

std::ranges::for_each(
outer,
[](auto&amp;&amp; inner) {
// <span style="color:#C80000;font-weight:bold">error: passing 'const filter_view' as 'this' argument discards qualifiers</span>
for (auto&amp;&amp; elem : inner)
std::cout &lt;&lt; elem &lt;&lt; " ";
});
}
</pre></blockquote>
<p>
In the above example, <tt>ranges::for_each</tt> requires <tt>indirect_unary_predicate&lt;Pred, projected&lt;I, identity&gt;&gt;</tt>
which ultimately requires <tt>invocable&lt;Pred&amp;, iter_common_reference_t&lt;projected&lt;I, identity&gt;&gt;&gt;</tt>.
<p/>
According to the current wording, the reference and value type of <tt>projected&lt;I, identity&gt;</tt> are <tt>filter_view&amp;&amp;</tt>
and <tt>filter_view&amp;</tt> respectively, which causes its common reference to be eventually calculated as
<tt>const filter_view&amp;</tt>. Since the former is not <tt>const</tt>-iterable, this results in a hard error during
instantiation because <tt>const begin</tt> is called unexpectedly in an unconstrained lambda.
</p>
<p>
It seems like having <tt>projected&lt;I, identity&gt;</tt> just be <tt>I</tt> is a more appropriate choice,
which makes the concept checking really specific to <tt>I</tt> rather than a potentially incomplete iterator wrapper.
</p>
</discussion>

<resolution>
<p>
This wording is relative to <paper num="N4958"/>.
</p>

<ol>

<li><p>Modify <sref ref="[projected]"/> as indicated:</p>

<blockquote>
<p>
-1- Class template <tt>projected</tt> is used to constrain algorithms that accept callable objects and projections
(<sref ref="[defns.projection]"/>). It combines an <tt>indirectly_readable</tt> type <tt>I</tt> and a callable
object type <tt>Proj</tt> into a new <tt>indirectly_readable</tt> type whose <tt>reference</tt> type is the
result of applying <tt>Proj</tt> to the <tt>iter_reference_t</tt> of <tt>I</tt>.
</p>
<blockquote><pre>
namespace std {
template&lt;class I, class Proj&gt;
struct <i>projected-impl</i> { // <i>exposition only</i>
struct <i>type</i> { // <i>exposition only</i>
using value_type = remove_cvref_t&lt;indirect_result_t&lt;Proj&amp;, I&gt;&gt;;
using difference_type = iter_difference_t&lt;I&gt;; // <i>present only if</i> I
// <i>models</i> weakly_incrementable
indirect_result_t&lt;Proj&amp;, I&gt; operator*() const; // <i>not defined</i>
};
};

template&lt;indirectly_readable I, indirectly_regular_unary_invocable&lt;I&gt; Proj&gt;
using projected = <ins>conditional_t&lt;is_same_v&lt;Proj, identity&gt;, I, typename</ins> <i>projected-impl</i>&lt;I, Proj&gt;::type<ins>&gt;</ins>;
}
</pre></blockquote>
</blockquote>


</li>

</ol>
</resolution>

</issue>

0 comments on commit 62b66f4

Please sign in to comment.