@@ -14,10 +14,10 @@ Currently the wording in <sref ref="[func.wrap.general]"/> allows implementation
14
14
to avoid double indirection when constructing owning functions wrappers from another one:
15
15
</p >
16
16
<blockquote >
17
- <p >
17
+ <p >
18
18
-2- Let <tt >t</tt > be an object of a type that is a specialization of <tt >function</tt >,
19
19
<tt >copyable_function</tt >, or <tt >move_only_function</tt >, such that the target object
20
- <tt >x</tt > of <tt >t</tt > has a type that is a specialization of <tt >function</tt >,
20
+ <tt >x</tt > of <tt >t</tt > has a type that is a specialization of <tt >function</tt >,
21
21
<tt >copyable_function</tt >, or <tt >move_only_function</tt >.
22
22
Each argument of the invocation of <tt >x</tt > evaluated as part of the invocation of <tt >t</tt >
23
23
may alias an argument in the same position in the invocation of <tt >t</tt > that has the same type,
@@ -38,6 +38,131 @@ an implementation to perform such an optimization. As a consequence, it is accep
38
38
to specify the allowance for all combinations of polymorphic wrappers, even for creating an
39
39
owning wrapper from a non-owning one, where implementing such an optimization may not be possible.
40
40
</p >
41
+
42
+ <superseded >
43
+ <p >
44
+ This wording is relative to <paper num =" N5008" />.
45
+ </p >
46
+ <ol >
47
+
48
+ <li ><p >Modify <sref ref =" [func.wrap.general]" /> as indicated:</p >
49
+
50
+ <blockquote >
51
+ <p >
52
+ -2- Let <tt >t</tt > be an object of a type that is a specialization of <tt >function</tt >,
53
+ <tt >copyable_function</tt >, <del >or</del > <tt >move_only_function</tt ><ins >, or <tt >function_ref</tt ></ins >,
54
+ such that the target object <tt >x</tt > of <tt >t</tt > has a type that is a specialization of <tt >function</tt >,
55
+ <tt >copyable_function</tt >, <del >or</del ><tt >move_only_function</tt ><ins >, or <tt >function_ref</tt ></ins >.
56
+ Each argument of the invocation of <tt >x</tt > evaluated as part of the invocation of <tt >t</tt >
57
+ may alias an argument in the same position in the invocation of <tt >t</tt > that has the same type,
58
+ even if the corresponding parameter is not of reference type.
59
+ </p >
60
+ </blockquote >
61
+
62
+ </li >
63
+ </ol >
64
+
65
+ </superseded >
66
+
67
+ <note >2024-05-21; Tomasz's comment and upates proposed resolution</note >
68
+
69
+ <p >
70
+ After implementing double indirection avoidance in the libstdc++, I have realized
71
+ that above wording change is insufficient to cover all user observable effects of
72
+ the change. Revelant quote from the <a href =" https://gcc.gnu.org/pipermail/libstdc++/2025-May/061561.html" >
73
+ Avoid double indirection in function_ref</a > from libstdc++ mailing lists:
74
+ </p >
75
+
76
+ <blockquote >
77
+ <p >
78
+ To avoidance of double indirection requires that constructed <tt >function_ref</tt >,
79
+ refers directly to the target function of the source, instead of source,
80
+ and this is visible after the assigment:
81
+ </p >
82
+
83
+ <pre >
84
+ void foo() noexcept;
85
+ void bar() noexcept;
86
+
87
+ std::function_ref< void() noexcept> sr(& foo);
88
+ std::function_ref< void()> dr(sr);
89
+ dr(); // calls `foo` regardless of implementation
90
+
91
+ sr = & bar;
92
+ sr(); // calls `bar`
93
+ dr(); // still calls `foo` if we avoid indirection,
94
+ // calls `bar` if we do not
95
+ </pre >
96
+
97
+ <p >
98
+ Similary for <tt >move_only_function</tt >/<tt >copyable_function</tt > source:
99
+ </p >
100
+
101
+ <pre >
102
+ std::move_only_function< void()> sm;
103
+ std::function_ref< void()> dm(sm);
104
+
105
+ dm(); // UB because `sm` is empty
106
+
107
+ sm = & foo;
108
+
109
+ dm(); // remains UB if we avoid indirection,
110
+ // calls `bar` if we do not.
111
+ </pre >
112
+
113
+ <p >
114
+ While we may want to allow skipping indirection for function_ref,
115
+ as this produces same behavior as in case for copy constructor (matching
116
+ signatures):
117
+ </p >
118
+
119
+ <pre >
120
+ void foo() noexcept;
121
+ void bar() noexcept;
122
+
123
+ std::function_ref< void() noexcept> sr(& foo);
124
+ std::function_ref< void() noexcept> dr(sr); // copy-cosntructor
125
+ dr(); // calls `foo` regardless of implementation
126
+
127
+ sr = & bar;
128
+ sr(); // calls `bar`
129
+ dr(); // still calls `foo` if we avoid indirection
130
+ </pre >
131
+
132
+
133
+ <p >
134
+ I do not think this is acceptable for <tt >move_only_function</tt >.
135
+ …
136
+ </p >
137
+
138
+ <p >
139
+ Note that for the same reason, implementations are not free to avoid
140
+ dangling when constructing <tt >function_ref</tt > from <tt >reference_wrapper</tt >:
141
+ </p >
142
+
143
+ <pre >
144
+ auto srw = std::ref(& foo);
145
+ std::function_ref< void()> drw(srw);
146
+ drw(); // calls `foo`
147
+
148
+ srw = std::ref(& bar);
149
+ drw(); // calls `foo` if we unwrap referenc wrapper,
150
+ // calls `bar` otherwise.
151
+ </pre >
152
+
153
+ <p >
154
+ Note that this is limited to <tt >function_ref</tt > due reference nature of this
155
+ wrapper.
156
+ </p >
157
+
158
+ </blockquote >
159
+
160
+ <p >
161
+ The updated resolution allows indirection but making it unspecified if
162
+ <tt >function_ref</tt > constructed from other <tt >function_ref</tt > specialization,
163
+ will refer to source object or its target.
164
+ </p >
165
+
41
166
</discussion >
42
167
43
168
<resolution >
@@ -49,20 +174,56 @@ This wording is relative to <paper num="N5008"/>.
49
174
<li ><p >Modify <sref ref =" [func.wrap.general]" /> as indicated:</p >
50
175
51
176
<blockquote >
52
- <p >
177
+ <p >
53
178
-2- Let <tt >t</tt > be an object of a type that is a specialization of <tt >function</tt >,
54
179
<tt >copyable_function</tt >, <del >or</del > <tt >move_only_function</tt ><ins >, or <tt >function_ref</tt ></ins >,
55
- such that the target object <tt >x</tt > of <tt >t</tt > has a type that is a specialization of <tt >function</tt >,
180
+ such that the target object <tt >x</tt > of <tt >t</tt > has a type that is a specialization of <tt >function</tt >,
56
181
<tt >copyable_function</tt >, <del >or</del ><tt >move_only_function</tt ><ins >, or <tt >function_ref</tt ></ins >.
57
182
Each argument of the invocation of <tt >x</tt > evaluated as part of the invocation of <tt >t</tt >
58
183
may alias an argument in the same position in the invocation of <tt >t</tt > that has the same type,
59
184
even if the corresponding parameter is not of reference type.
60
185
</p >
61
186
</blockquote >
62
187
188
+ </li >
189
+
190
+ <li ><p >Modify <sref ref =" [func.wrap.ref.ctor]" /> as indicated:</p >
191
+
192
+ <blockquote >
193
+ <pre >
194
+ template< class F> constexpr function_ref(F&& ) noexcept;
195
+ </pre >
196
+ <blockquote >
197
+ [… ]
198
+ <p >-7- <i >Effects</i >:
199
+ Initializes <tt ><i >bound-entity</i ></tt > with <tt >addressof(f)</tt >
200
+ and <tt ><i >thunk-ptr</i ></tt > with the address of a function <tt ><i >thunk</i ></tt > such that
201
+ <tt ><i >thunk</i >(<i >bound-entity</i >, <i >call-args</i >...)</tt > is expression-equivalent
202
+ (<sref ref =" [defns.expression.equivalent]" />) to
203
+ <tt >invoke_r< R> (static_cast< cv T&> (f), <i >call-args</i >...)</tt >.
204
+ </p >
205
+ <ins ><p >-X- <i >Remarks</i >:
206
+ If <tt >remove_cveref_t< F> </tt > is specialization of <tt >function_ref</tt > implementation
207
+ may initialize <tt ><i >bound-entity</i ></tt > with <tt ><i >bound-entity</i ></tt > of <tt >f</tt >.
208
+ [<i >Example:</i >:</p >
209
+ <pre >
210
+ void f1() noexcept;
211
+ void f2() noexcept;
212
+
213
+ function_ref< void() noexcept> r1(& r1);
214
+ function_ref< void()> r2(r1);
215
+ r1 = & f2;
216
+ f2(); // it is unspecified if `f1` or `f2` is invoked
217
+ </pre >
218
+ <p > — <i >end example</i >]</p >
219
+ </ins >
220
+ </blockquote >
221
+ </blockquote >
222
+
63
223
</li >
64
224
</ol >
65
225
226
+
66
227
</resolution >
67
228
68
- </issue >
229
+ </issue >
0 commit comments