Skip to content

Commit

Permalink
New issue from Hewill Kang: " adaptor(args...)(r) is not equivalent t…
Browse files Browse the repository at this point in the history
…o std::bind_back(adaptor, args...)(r)"
  • Loading branch information
Dani-Hub committed Oct 14, 2023
1 parent 955cc46 commit 005c863
Showing 1 changed file with 70 additions and 0 deletions.
70 changes: 70 additions & 0 deletions xml/issue3994.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?xml version='1.0' encoding='utf-8' standalone='no'?>
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">

<issue num="3994" status="New">
<title><tt>adaptor(args...)(r)</tt> is not equivalent to <tt>std::bind_back(adaptor, args...)(r)</tt></title>
<section><sref ref="[range.adaptor.object]"/></section>
<submitter>Hewill Kang</submitter>
<date>11 Oct 2023</date>
<priority>99</priority>

<discussion>
<p>
<sref ref="[range.adaptor.object]"/> p8 specifies that:
</p>
<blockquote><p>
The expression <tt>adaptor(args...)</tt> produces a range adaptor closure object <tt>f</tt> that is a perfect forwarding
call wrapper (<sref ref="[func.require]"/>) with the following properties:
</p></blockquote>
<p>
According to the subsequent description, it can be inferred that the behavior is similar to
<tt>std::bind_back(adaptor, args...)</tt> which also returns a perfect forwarding call wrapper.
<p/>
Among them, "A <i>perfect forwarding call wrapper</i> is an argument forwarding call wrapper
that forwards its state entities to the underlying call expression" according to <a href="https://wg21.link/func.require">[func.require]</a>/4, and call wrapper in <a href="https://wg21.link/func.require">[func.require]</a>/3 is described as:
</p>
<blockquote><p>
Every call wrapper (<sref ref="[func.def]"/>) meets the <i>Cpp17MoveConstructible</i> and <i>Cpp17Destructible</i> requirements.
</p></blockquote>
<p>
In order to conform with the specification, standard functions that return perfect forwarding call wrappers such as
<tt>std::bind_front/back</tt> and <tt>std::not_fn</tt> all <i>Mandates</i> that
<tt>(is_constructible_v&lt;BoundArgs, Args&gt; &amp;&amp; ...)</tt> and
<tt>(is_move_constructible_v&lt;BoundArgs&gt; &amp;&amp; ...)</tt> are each <tt>true</tt>,
the former condition corresponds to <sref ref="[range.adaptor.object]"/> p8:
</p>
<blockquote><p>
The expression <tt>adaptor(args...)</tt> is well-formed if and only if the initialization of the bound argument
entities of the result, as specified above, are all well-formed.
</p></blockquote>
<p>
However, the latter does not have a corresponding description in <tt>&lt;ranges&gt;</tt>. In other words, range
adaptor objects do not explicitly indicate that the bound argument must be move-constructible.
This results in implementation divergence for some uncommon types (<a href="https://godbolt.org/z/r6Gq8W6qe">demo</a>):
</p>
<blockquote><pre>
#include &lt;ranges&gt;
#include &lt;string_view&gt;

constexpr struct WeirdFive {
WeirdFive() = default;
WeirdFive(const WeirdFive&amp;) = default;
constexpr operator int() const { return 5; }

WeirdFive(WeirdFive&amp;&amp;) = delete;
} five;

constexpr std::string_view sv{"hello"};
static_assert(sv == std::views::take(five)(sv)); // <span style="color:red;font-weight:bolder">libstdc++/libc++ reject, MSVC-STL accepts</span>
</pre></blockquote>
<p>
Above, libstdc++ always moves arguments into internal members, which leads to hard errors in the member initializer list;
libc++ uses <tt>std::bind_back</tt> for argument binding, which also leads to hard errors in the function body as the
former requires arguments to be move-constructible; MSVC-STL is the most compliant with current wording.
</p>
</discussion>

<resolution>
</resolution>

</issue>

0 comments on commit 005c863

Please sign in to comment.