@@ -14,10 +14,10 @@ Currently the wording in <sref ref="[func.wrap.general]"/> allows implementation
1414to avoid double indirection when constructing owning functions wrappers from another one:
1515</p >
1616<blockquote >
17- <p >
17+ <p >
1818-2- Let <tt >t</tt > be an object of a type that is a specialization of <tt >function</tt >,
1919<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 >,
2121<tt >copyable_function</tt >, or <tt >move_only_function</tt >.
2222Each argument of the invocation of <tt >x</tt > evaluated as part of the invocation of <tt >t</tt >
2323may 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
3838to specify the allowance for all combinations of polymorphic wrappers, even for creating an
3939owning wrapper from a non-owning one, where implementing such an optimization may not be possible.
4040</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+
41166</discussion >
42167
43168<resolution >
@@ -49,20 +174,56 @@ This wording is relative to <paper num="N5008"/>.
49174<li ><p >Modify <sref ref =" [func.wrap.general]" /> as indicated:</p >
50175
51176<blockquote >
52- <p >
177+ <p >
53178-2- Let <tt >t</tt > be an object of a type that is a specialization of <tt >function</tt >,
54179<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 >,
56181<tt >copyable_function</tt >, <del >or</del ><tt >move_only_function</tt ><ins >, or <tt >function_ref</tt ></ins >.
57182Each argument of the invocation of <tt >x</tt > evaluated as part of the invocation of <tt >t</tt >
58183may alias an argument in the same position in the invocation of <tt >t</tt > that has the same type,
59184even if the corresponding parameter is not of reference type.
60185</p >
61186</blockquote >
62187
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+
63223</li >
64224</ol >
65225
226+
66227</resolution >
67228
68- </issue >
229+ </issue >
0 commit comments