Skip to content

Commit e6bbd2f

Browse files
committed
New issue from Tomasz: "Supporting copy-elision in function wrappers"
1 parent 2d8812f commit e6bbd2f

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

xml/issue4319.xml

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?xml version='1.0' encoding='utf-8' standalone='no'?>
2+
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
3+
4+
<issue num="4319" status="New">
5+
<title>Supporting copy-elision in function wrappers</title>
6+
<section>
7+
<sref ref="[func.require]"/>
8+
</section>
9+
<submitter>Tomasz Kamiński</submitter>
10+
<date>19 Aug 2025</date>
11+
<priority>99</priority>
12+
13+
<discussion>
14+
<p>
15+
The wording for argument forwarding call wrappers in <sref ref="[func.require]"/> p3,
16+
</p>
17+
<blockquote><p>
18+
This forwarding step delivers rvalue arguments as rvalue references and lvalue arguments as lvalue references.
19+
</p></blockquote>
20+
<p>
21+
requires that each wrapper binds a temporary to rvalue reference
22+
(materializing it), and then pass that xvalue. This essentially
23+
codifies an implementation where wrappers provide an `operator()` that
24+
accepts <tt>Args&amp;&amp;...</tt>. This is fine for most of the wrappers.
25+
<p/>
26+
For some wrappers more efficient implementation strategies are possible:
27+
</p>
28+
<ul>
29+
<li><p>`bind_front(f)/bind_back(f)` without bound args could return a copy of `f`</p></li>
30+
<li><p><tt>bind_front&lt;f&gt;()/bind_back&lt;f&gt;</tt> could produce a
31+
<tt>__function_wrapper&lt;f&gt;</tt>, that for function pointers can be invoked using
32+
a surrogate function call.</p></li>
33+
</ul>
34+
<p>
35+
However, such implementation strategies are currently disallowed per
36+
<sref ref="[func.require]"/> p3, as invoking the function wrapper with
37+
a prvalue `bind_front(f)(T())` requires a temporary to be materialized,
38+
and then moved into the parameter of `f`. For example:
39+
</p>
40+
<blockquote><pre>
41+
struct M
42+
{
43+
M() { std::cout &lt;&lt; "Default" &lt; std::endl; }
44+
M(M&amp;&amp; m) { std::cout &lt;&lt; "Move" &lt; std::endl; }
45+
};
46+
47+
struct F
48+
{
49+
void operator()(M m) {}
50+
} f;
51+
</pre></blockquote>
52+
<p>
53+
The call `f(M{})` will print only "`Default`" but `bind_front(f)(M{})` is
54+
required to produce "`Default`" and "`Move`". We should allow
55+
implementations to elide the move operations, but not require it.
56+
</p>
57+
</discussion>
58+
59+
<resolution>
60+
<p>
61+
This wording is relative to <paper num="N5014"/>.
62+
</p>
63+
64+
<ol>
65+
66+
<li><p>Modify <sref ref="[func.require]"/> as indicated:</p>
67+
68+
<blockquote>
69+
<p>
70+
-3- Every call wrapper (<sref ref="[func.def]"/>) meets the <i>Cpp17MoveConstructible</i> and
71+
<i>Cpp17Destructible</i> requirements. An <i>argument forwarding call wrapper</i> is a call wrapper
72+
that can be called with an arbitrary argument list and delivers the arguments to the target object
73+
<del>as references</del>. This forwarding step delivers <del>rvalue arguments as rvalue references
74+
and lvalue arguments as lvalue references.</del><ins>:</ins>
75+
</p>
76+
<ol style="list-style-type: none">
77+
<li><p><ins>(3.?) &mdash; lvalue arguments as lvalues,</ins></p></li>
78+
<li><p><ins>(3.?) &mdash; xvalue arguments as xvalues,</ins></p></li>
79+
<li><p><ins>(3.?) &mdash; prvalue arguments as either prvalues or xvalues</ins></p></li>
80+
</ol>
81+
</blockquote>
82+
83+
</li>
84+
85+
</ol>
86+
</resolution>
87+
88+
</issue>

0 commit comments

Comments
 (0)