Topic: Proposal - "function_ref: a non-owning reference to a Callable
Author: Vittorio Romeo <vittorio.romeo.vee@gmail.com>
Date: Sat, 15 Jul 2017 09:25:49 -0700 (PDT)
Raw View
------=_Part_239_898686295.1500135949376
Content-Type: multipart/alternative;
boundary="----=_Part_240_1844682464.1500135949376"
------=_Part_240_1844682464.1500135949376
Content-Type: text/plain; charset="UTF-8"
Hello everyone - I'm looking for feedback on my *"function_ref: a
non-owning reference to a Callable"* proposal. In short, this paper
proposes the addition of something like `std::string_view` for functions, a
lightweight type-erased reference vocabulary type that's especially useful
when used as a function parameter.
I wrote an article with a toy implementation in the past:
https://vittorioromeo.info/index/blog/passing_functions_to_functions.html
Jonathan Muller wrote two related posts:
http://foonathan.net/blog/2017/01/20/function-ref-implementation.html
http://foonathan.net/blog/2017/03/22/string_view-temporary.html
Some earlier discussions can be found here:
https://groups.google.com/a/isocpp.org/forum/?fromgroups#!searchin/std-proposals/function_ref/std-proposals/vven2Om7Ha8/_vTUvwSzBgAJ
https://groups.google.com/a/isocpp.org/forum/?fromgroups#!searchin/std-proposals/function_ref/std-proposals/vMvzAl0a-P8/fbx1POVBCAAJ
https://twitter.com/ericniebler/status/880899867035394048
Thanks!
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/824f059e-467b-45a7-9746-b65c2f144d62%40isocpp.org.
------=_Part_240_1844682464.1500135949376
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Hello everyone - I'm looking for feedback on my=C2=A0<=
i>"function_ref: a non-owning reference to a Callable"</i> propos=
al. In short, this paper proposes the addition of something like `std::stri=
ng_view` for functions, a lightweight type-erased reference vocabulary type=
that's=C2=A0especially useful when used as a function parameter.<br><b=
r>I wrote an article with a toy implementation in the past:<br>https://vitt=
orioromeo.info/index/blog/passing_functions_to_functions.html<br><br>Jonath=
an Muller wrote two related posts:<br>http://foonathan.net/blog/2017/01/20/=
function-ref-implementation.html<br>http://foonathan.net/blog/2017/03/22/st=
ring_view-temporary.html<br><br>Some earlier discussions can be found here:=
<br>https://groups.google.com/a/isocpp.org/forum/?fromgroups#!searchin/std-=
proposals/function_ref/std-proposals/vven2Om7Ha8/_vTUvwSzBgAJ<br>https://gr=
oups.google.com/a/isocpp.org/forum/?fromgroups#!searchin/std-proposals/func=
tion_ref/std-proposals/vMvzAl0a-P8/fbx1POVBCAAJ<br>https://twitter.com/eric=
niebler/status/880899867035394048<br><br>Thanks!</div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/824f059e-467b-45a7-9746-b65c2f144d62%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/824f059e-467b-45a7-9746-b65c2f144d62=
%40isocpp.org</a>.<br />
------=_Part_240_1844682464.1500135949376--
------=_Part_239_898686295.1500135949376
Content-Type: text/html; charset=UTF-8;
name=proposal_function_ref_draft0.html
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename=proposal_function_ref_draft0.html
X-Attachment-Id: b205dea3-dc54-4b02-a1ea-47c4fbabc5ef
Content-ID: <b205dea3-dc54-4b02-a1ea-47c4fbabc5ef>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- saved from url=3D(0044)https://vittorioromeo.info/Misc/fnview4.html --=
>
<html xmlns=3D"http://www.w3.org/1999/xhtml"><head><meta http-equiv=3D"Cont=
ent-Type" content=3D"text/html; charset=3DUTF-8">
=20
<meta http-equiv=3D"Content-Style-Type" content=3D"text/css">
<meta name=3D"generator" content=3D"pandoc">
<meta name=3D"author" content=3D"Vittorio Romeo | vittorio.romeo@outlook.=
com">
<title>function_ref: a non-owning reference to a Callable</title>
<style type=3D"text/css">code{white-space: pre;}</style>
<style type=3D"text/css">
div.sourceCode { overflow-x: auto; }
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; =
color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
code > span.dt { color: #902000; } /* DataType */
code > span.dv { color: #40a070; } /* DecVal */
code > span.bn { color: #40a070; } /* BaseN */
code > span.fl { color: #40a070; } /* Float */
code > span.ch { color: #4070a0; } /* Char */
code > span.st { color: #4070a0; } /* String */
code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
code > span.ot { color: #007020; } /* Other */
code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
code > span.fu { color: #06287e; } /* Function */
code > span.er { color: #ff0000; font-weight: bold; } /* Error */
code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /=
* Warning */
code > span.cn { color: #880000; } /* Constant */
code > span.sc { color: #4070a0; } /* SpecialChar */
code > span.vs { color: #4070a0; } /* VerbatimString */
code > span.ss { color: #bb6688; } /* SpecialString */
code > span.im { } /* Import */
code > span.va { color: #19177c; } /* Variable */
code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code > span.op { color: #666666; } /* Operator */
code > span.bu { } /* BuiltIn */
code > span.ex { } /* Extension */
code > span.pp { color: #bc7a00; } /* Preprocessor */
code > span.at { color: #7d9029; } /* Attribute */
code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /=
* Annotation */
code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /=
* CommentVar */
code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /=
* Information */
</style>
<link href=3D"data:text/css;charset=3Dutf-8,pre%2EsourceCode%7Bborder%3A1=
px%20solid%20%23444%3Bpadding%3A12px%3Bborder%2Dradius%3A6px%7Dhtml%7Bfont%=
2Dsize%3A100%25%3Boverflow%2Dy%3Ascroll%3B%2Dwebkit%2Dtext%2Dsize%2Dadjust%=
3A100%25%3B%2Dms%2Dtext%2Dsize%2Dadjust%3A100%25%7Dbody%7Bcolor%3A%23444%3B=
font%2Dfamily%3Ageorgia%2Cpalatino%2Cpalatino%20linotype%2Ctimes%2Ctimes%20=
new%20roman%2Cserif%3Bfont%2Dsize%3A12px%3Bline%2Dheight%3A1%2E7%3Bpadding%=
3A1em%3Bmargin%3Aauto%3Bmax%2Dwidth%3A54em%3Bbackground%3A%23fefefe%7Da%7Bc=
olor%3A%230645ad%3Btext%2Ddecoration%3Anone%7Da%3Avisited%7Bcolor%3A%230b00=
80%7Da%3Ahover%7Bcolor%3A%2306e%7Da%3Aactive%7Bcolor%3A%23faa700%7Da%3Afocu=
s%7Boutline%3Athin%20dotted%7D%2A%3A%3A%2Dmoz%2Dselection%7Bbackground%3Arg=
ba%28255%2C255%2C0%2C%2E3%29%3Bcolor%3A%23000%7D%2A%3A%3Aselection%7Bbackgr=
ound%3Argba%28255%2C255%2C0%2C%2E3%29%3Bcolor%3A%23000%7Da%3A%3A%2Dmoz%2Dse=
lection%7Bbackground%3Argba%28255%2C255%2C0%2C%2E3%29%3Bcolor%3A%230645ad%7=
Da%3A%3Aselection%7Bbackground%3Argba%28255%2C255%2C0%2C%2E3%29%3Bcolor%3A%=
230645ad%7Dp%7Bmargin%3A1em%200%7Dimg%7Bmax%2Dwidth%3A100%25%7Dh1%2Ch2%2Ch3=
%2Ch4%2Ch5%2Ch6%7Bcolor%3A%23111%3Bline%2Dheight%3A125%25%3Bmargin%2Dtop%3A=
2em%3Bfont%2Dweight%3A400%7Dh4%2Ch5%2Ch6%7Bfont%2Dweight%3A700%7Dh1%7Bfont%=
2Dsize%3A2%2E5em%7Dh2%7Bfont%2Dsize%3A2em%7Dh3%7Bfont%2Dsize%3A1%2E5em%7Dh4=
%7Bfont%2Dsize%3A1%2E2em%7Dh5%7Bfont%2Dsize%3A1em%7Dh6%7Bfont%2Dsize%3A%2E9=
em%7Dblockquote%7Bcolor%3A%23666%3Bmargin%3A0%3Bpadding%2Dleft%3A3em%3Bbord=
er%2Dleft%3A%2E5em%20%23eee%20solid%7Dhr%7Bdisplay%3Ablock%3Bheight%3A2px%3=
Bborder%3A0%3Bborder%2Dtop%3A1px%20solid%20%23aaa%3Bborder%2Dbottom%3A1px%2=
0solid%20%23eee%3Bmargin%3A1em%200%3Bpadding%3A0%7Dpre%2Ccode%2Ckbd%2Csamp%=
7Bcolor%3A%23000%3Bfont%2Dfamily%3Amonospace%2Cmonospace%3B%5Ffont%2Dfamily=
%3A%27courier%20new%27%2Cmonospace%3Bfont%2Dsize%3A%2E98em%7Dpre%7Bwhite%2D=
space%3Apre%3Bwhite%2Dspace%3Apre%2Dwrap%3Bword%2Dwrap%3Abreak%2Dword%7Db%2=
Cstrong%7Bfont%2Dweight%3A700%7Ddfn%7Bfont%2Dstyle%3Aitalic%7Dins%7Bbackgro=
und%3A%23ff9%3Bcolor%3A%23000%3Btext%2Ddecoration%3Anone%7Dmark%7Bbackgroun=
d%3A%23ff0%3Bcolor%3A%23000%3Bfont%2Dstyle%3Aitalic%3Bfont%2Dweight%3A700%7=
Dsub%2Csup%7Bfont%2Dsize%3A75%25%3Bline%2Dheight%3A0%3Bposition%3Arelative%=
3Bvertical%2Dalign%3Abaseline%7Dsup%7Btop%3A%2D%2E5em%7Dsub%7Bbottom%3A%2D%=
2E25em%7Dul%2Col%7Bmargin%3A1em%200%3Bpadding%3A0%200%200%202em%7Dli%20p%3A=
last%2Dchild%7Bmargin%2Dbottom%3A0%7Dul%20ul%2Col%20ol%7Bmargin%3A%2E3em%20=
0%7Ddl%7Bmargin%2Dbottom%3A1em%7Ddt%7Bfont%2Dweight%3A700%3Bmargin%2Dbottom=
%3A%2E8em%7Ddd%7Bmargin%3A0%200%20%2E8em%202em%7Ddd%3Alast%2Dchild%7Bmargin=
%2Dbottom%3A0%7Dimg%7Bborder%3A0%3B%2Dms%2Dinterpolation%2Dmode%3Abicubic%3=
Bvertical%2Dalign%3Amiddle%7Dfigure%7Bdisplay%3Ablock%3Btext%2Dalign%3Acent=
er%3Bmargin%3A1em%200%7Dfigure%20img%7Bborder%3A0%3Bmargin%3A0%20auto%7Dfig=
caption%7Bfont%2Dsize%3A%2E8em%3Bfont%2Dstyle%3Aitalic%3Bmargin%3A0%200%20%=
2E8em%7Dtable%7Bmargin%2Dbottom%3A2em%3Bborder%2Dbottom%3A1px%20solid%20%23=
ddd%3Bborder%2Dright%3A1px%20solid%20%23ddd%3Bborder%2Dspacing%3A0%3Bborder=
%2Dcollapse%3Acollapse%7Dtable%20th%7Bpadding%3A%2E2em%201em%3Bbackground%2=
Dcolor%3A%23eee%3Bborder%2Dtop%3A1px%20solid%20%23ddd%3Bborder%2Dleft%3A1px=
%20solid%20%23ddd%7Dtable%20td%7Bpadding%3A%2E2em%201em%3Bborder%2Dtop%3A1p=
x%20solid%20%23ddd%3Bborder%2Dleft%3A1px%20solid%20%23ddd%3Bvertical%2Dalig=
n%3Atop%7D%2Eauthor%7Bfont%2Dsize%3A1%2E2em%3Btext%2Dalign%3Acenter%7D%40me=
dia%20only%20screen%20and%20%28min%2Dwidth%3A480px%29%7Bbody%7Bfont%2Dsize%=
3A14px%7D%7D%40media%20only%20screen%20and%20%28min%2Dwidth%3A768px%29%7Bbo=
dy%7Bfont%2Dsize%3A16px%7D%7D%40media%20print%7B%2A%7Bbackground%3Atranspar=
ent%21important%3Bcolor%3A%23000%21important%3Bfilter%3Anone%21important%3B=
%2Dms%2Dfilter%3Anone%21important%7Dbody%7Bfont%2Dsize%3A12pt%3Bmax%2Dwidth=
%3A100%25%7Da%2Ca%3Avisited%7Btext%2Ddecoration%3Aunderline%7Dhr%7Bheight%3=
A1px%3Bborder%3A0%3Bborder%2Dbottom%3A1px%20solid%20%23000%7Da%5Bhref%5D%3A=
after%7Bcontent%3A%22%20%28%22%20attr%28href%29%20%22%29%22%7Dabbr%5Btitle%=
5D%3Aafter%7Bcontent%3A%22%20%28%22%20attr%28title%29%20%22%29%22%7D%2Eir%2=
0a%3Aafter%2Ca%5Bhref%5E%3D%22javascript%3A%22%5D%3Aafter%2Ca%5Bhref%5E%3D%=
22%23%22%5D%3Aafter%7Bcontent%3A%22%22%7Dpre%2Cblockquote%7Bborder%3A1px%20=
solid%20%23999%3Bpadding%2Dright%3A1em%3Bpage%2Dbreak%2Dinside%3Aavoid%7Dtr=
%2Cimg%7Bpage%2Dbreak%2Dinside%3Aavoid%7Dimg%7Bmax%2Dwidth%3A100%25%21impor=
tant%7D%40page%3Aleft%7Bmargin%3A15mm%2020mm%2015mm%2010mm%7D%40page%3Arigh=
t%7Bmargin%3A15mm%2010mm%2015mm%2020mm%7Dp%2Ch2%2Ch3%7Borphans%3A3%3Bwidows=
%3A3%7Dh2%2Ch3%7Bpage%2Dbreak%2Dafter%3Aavoid%7D%7D" rel=3D"stylesheet" typ=
e=3D"text/css">
<style type=3D"text/css">
:root #header + #content > #left > #rlblock_left
{ display: none !important; }</style></head>
<body>
<div id=3D"header">
<h1 class=3D"title"><code>function_ref</code>: a non-owning reference to a =
<code>Callable</code></h1>
<h2 class=3D"author">Vittorio Romeo | <a href=3D"mailto:vittorio.romeo@outl=
ook.com">vittorio.romeo@outlook.com</a></h2>
</div>
<style>
..inline-link
{
font-size: small;
margin-top: -2.1em;
text-align: right;
font-weight: bold;
}
code
{
font-family: "Fira Code", monospace !important;
font-size: 0.87em;
}
..sourceCode
{
font-size: 0.95em;
}
a code
{
color: #0645ad;
}
</style>
<p><em>(DRAFT)</em></p>
<h2 id=3D"abstract">Abstract</h2>
<p>This paper proposes the addition of <code>function_ref<R(Args...)>=
</code> to the Standard Library, a <em>"vocabulary type"</em> for non-ownin=
g references to <code>Callable</code> objects.</p>
<h2 id=3D"overview">Overview</h2>
<p>Since the advent of C++11 writing more functional code has become easier=
: functional programming patterns and idioms have become powerful additions=
to the C++ developer's toolbox. <strong>"Higher-order functions"</strong> =
are one of the key ideas of the functional paradigm - in short, they are fu=
nctions that take functions as arguments and/or return functions as results=
..</p>
<p>The need of referring to an existing <code>Callable</code> object comes =
up often when writing functional C++ code, but the Standard Library unfortu=
nately doesn't provide a flexible facility that allows to do so. Let's cons=
ider the existing utilities:</p>
<ul>
<li><p><strong>Pointers to functions</strong> are only useful when the obje=
ct they refer to is stateless <em>(i.e. a non-member function or a capture-=
less lambda)</em>, but they are cumbersome to use otherwise. Fully supporti=
ng the <code>Callable</code> concept requires also explicitly dealing with =
<strong>pointers to member functions</strong> and <strong>pointers to data =
members</strong>.</p></li>
<li><p><strong><code>std::function</code></strong> seamlessly works with <c=
ode>Callable</code> objects, but it's a <em>"general-purpose polymorphic fu=
nction wrapper"</em> that may introduce unnecessary overhead and that <stro=
ng>owns</strong> the <code>Callable</code> it stores. <code>std::function</=
code> is a great choice when an owning type-erased wrapper is required, but=
it's often abused when its ownership semantics and its flexibility are not=
required.</p>
<ul>
<li>Note that when <code>std::function</code> is constructed/assigned with =
a <code>std::reference_wrapper</code> to a <code>Callable</code>, it has re=
ference semantics.</li>
</ul></li>
<li><p><strong>Templates</strong> can be used to avoid unnecessary costs an=
d to uniformly handle any <code>Callable</code> object, but they are hard t=
o constrain to a particular signature and force code to be defined in heade=
rs.</p></li>
</ul>
<p>This paper proposes the introduction of a new <code>function_ref</code> =
class template, which is akin to <code>std::string_view</code>. This paper =
describes <code>function_ref</code> as a <strong>non-owning lightweight wra=
pper</strong> over any <code>Callable</code> object.</p>
<h2 id=3D"motivating-example">Motivating example</h2>
<p>Here's one example use case that benefits from <em>higher-order function=
s</em>: a <code>retry(n, f)</code> function that attempts to synchronously =
call <code>f</code> up to <code>n</code> times until success. This example =
might model the real-world scenario of repeatedly querying a flaky web serv=
ice.</p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">struct</span> payload { <span class=3D"co">/=
* ... */</span> };
<span class=3D"co">// Repeatedly invokes `action` up to `times` repetitions=
..</span>
<span class=3D"co">// Immediately returns if `action` returns a valid `payl=
oad`.</span>
<span class=3D"co">// Returns `std::nullopt` otherwise.</span>
<span class=3D"bu">std::</span>optional<payload> retry(<span class=3D=
"bu">std::</span>size_t times, <span class=3D"co">/* ????? */</span> action=
);</code></pre></div>
<p>The passed-in <code>action</code> should be a <code>Callable</code> whic=
h takes no arguments and returns <code>std::optional<payload></code>.=
Let's see how <code>retry</code> can be implemented with various technique=
s:</p>
<ul>
<li><p>Using <em>pointers to functions</em>:</p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"bu">std::</span>optional<payload> retry(<s=
pan class=3D"bu">std::</span>size_t times,
<span class=3D"bu">std::</span>optional<pay=
load>(*action)())
{
<span class=3D"co">/* ... */</span>
}</code></pre></div>
<div class=3D"inline-link">
<p><a href=3D"https://godbolt.org/g/UQbZYp"><em>(on godbolt.org)</em></a></=
p>
</div>
<ul>
<li><p><strong>Advantages</strong>:</p>
<ul>
<li><p>Easy to implement: no need to use a <code>template</code> or any exp=
licit constraint <em>(e.g. <code>std::enable_if_t<...></code>)</em>. =
The type of the pointer specifies exactly which functions can be passed, no=
extra constraints are required.</p></li>
<li><p>Minimal overhead: no allocations, no exceptions, and <code>action</c=
ode> is as big as a pointer.</p>
<ul>
<li>Modern compilers are able to completely inline the call to <code>action=
</code>, producing optimal assembly.</li>
</ul></li>
</ul></li>
<li><p><strong>Drawbacks</strong>:</p>
<ul>
<li>This technique doesn't support stateful <code>Callable</code> objects.<=
/li>
</ul></li>
</ul></li>
<li><p>Using a <code>template</code>:</p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> F>
<span class=3D"kw">auto</span> retry(<span class=3D"bu">std::</span>size_t =
times, F&& action)
-> <span class=3D"bu">std::</span>enable_if_t<<span class=3D"bu">=
std::</span>is_invocable_r_v<<span class=3D"bu">std::</span>optional<=
payload>, F&&>,
<span class=3D"bu">std::</span>optional<payload&=
gt;>
{
<span class=3D"co">/* ... */</span>
}</code></pre></div>
<div class=3D"inline-link">
<p><a href=3D"https://godbolt.org/g/AGikkz"><em>(on godbolt.org)</em></a></=
p>
</div>
<ul>
<li><p><strong>Advantages</strong>:</p>
<ul>
<li><p>Supports arbitrary <code>Callable</code> objects, such as stateful c=
losures.</p></li>
<li><p>Zero-overhead: no allocations, no exceptions, no indirections.</p></=
li>
</ul></li>
<li><p><strong>Drawbacks</strong>:</p>
<ul>
<li><p>Harder to implement and less readable: users must use <code>std::ena=
ble_if_t</code> and <code>std::invocable_r_v</code> to ensure that <code>ac=
tion</code>'s signature is properly constrained.</p></li>
<li><p><code>retry</code> must be defined in a header file. This might be u=
ndesiderable when trying to minimize compilation times.</p></li>
</ul></li>
</ul></li>
<li><p>Using <code>std::function</code>:</p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"bu">std::</span>optional<payload> retry(<s=
pan class=3D"bu">std::</span>size_t times,
<span class=3D"bu">std::</span>function<<sp=
an class=3D"bu">std::</span>optional<payload>()> action)
{
<span class=3D"co">/* ... */</span>
}</code></pre></div>
<div class=3D"inline-link">
<p><a href=3D"https://godbolt.org/g/t9FH9b"><em>(on godbolt.org)</em></a></=
p>
</div>
<ul>
<li><p><strong>Advantages</strong>:</p>
<ul>
<li><p>Supports arbitrary <code>Callable</code> objects, such as stateful c=
losures.</p></li>
<li><p>Easy to implement: no need to use a <code>template</code> or any exp=
licit constraint. The type fully constrains what can be passed.</p></li>
</ul></li>
<li><p><strong>Drawbacks</strong>:</p>
<ul>
<li><p>Unclear ownership semantics: <code>action</code> might either own th=
e the stored <code>Callable</code>, or just refer to an existing <code>Call=
able</code> if initialized with a <code>std::reference_wrapper</code>.</p><=
/li>
<li><p>Can potentially have significant overhead:</p>
<ul>
<li><p>Even though the implementation makes use of SBO <em>(small buffer op=
timization)</em>, <code>std::function</code> might allocate if the stored o=
bject is large enough. This requires one extra branch on construction/assig=
nment, one potential dynamic allocation, and makes <code>action</code> as b=
ig as the size of the internal buffer.</p></li>
<li><p>If the implementation doesn't make use of SBO, <code>std::function</=
code> will always allocate on construction/assignment.</p></li>
<li><p>Modern compilers are not able to inline <code>std::function</code>, =
often resulting in very poor assembly compared to the previously mentioned =
techniques.</p></li>
</ul></li>
<li><p>Mandatory use of exceptions: <code>std::function</code> might throw =
if an allocation fails, and throws <code>std::bad_function_call</code> if i=
t's invoked while unset.</p></li>
</ul></li>
</ul></li>
<li><p>Using the proposed <code>function_ref</code>:</p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"bu">std::</span>optional<payload> retry(<s=
pan class=3D"bu">std::</span>size_t times,
function_ref<<span class=3D"bu">std::</span=
>optional<payload>()> action)
{
<span class=3D"co">/* ... */</span>
}</code></pre></div>
<div class=3D"inline-link">
<p><a href=3D"https://godbolt.org/g/DvWKVH"><em>(on godbolt.org)</em></a></=
p>
</div>
<ul>
<li><p><strong>Advantages</strong>:</p>
<ul>
<li><p>Supports arbitrary <code>Callable</code> objects, such as stateful c=
losures.</p></li>
<li><p>Easy to implement: no need to use a <code>template</code> or any con=
straint. The type fully constrains what can be passed.</p></li>
<li><p>Clear ownership semantics: <code>action</code> is a <strong>non-owni=
ng</strong> reference to an existing <code>Callable</code>.</p></li>
<li><p>Small overhead: no allocations, no exceptions, and <code>action</cod=
e> is as big as two pointers.</p>
<ul>
<li>Modern compilers are able to completely inline the call to <code>action=
</code>, producing optimal assembly.</li>
</ul></li>
</ul></li>
</ul></li>
</ul>
<h2 id=3D"impact-on-the-standard">Impact on the standard</h2>
<p>This proposal is a pure library extension. It does not require changes t=
o any existing part of the Standard.</p>
<h2 id=3D"alternatives">Alternatives</h2>
<p>The only existing viable alternative to <code>function_ref</code> curren=
tly is <code>std::function</code> + <code>std::reference_wrapper</code>. Th=
e Standard guarantees that when a <code>std::reference_wrapper</code> is us=
ed to construct/assign to a <code>std::function</code> no allocations will =
occur and no exceptions will be thrown.</p>
<p>Using <code>std::function</code> for non-owning references is suboptimal=
for various reasons.</p>
<ol style=3D"list-style-type: decimal">
<li><p>The ownership semantics of a <code>std::function</code> are unclear =
- they change depending on whether or not the <code>std::function</code> wa=
s constructed/assigned with a <code>std::reference_wrapper</code>.</p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"dt">void</span> foo(<span class=3D"bu">std::</sp=
an>function<<span class=3D"dt">void</span>()> f);
<span class=3D"co">// `f` could be referring to an existing Callable, or co=
uld own one.</span>
<span class=3D"dt">void</span> bar(function_ref<<span class=3D"dt">void<=
/span>()> f);
<span class=3D"co">// `f` unambiguously is a non-owning reference to an exi=
sting Callable.</span></code></pre></div></li>
<li><p>This technique doesn't work with temporaries. This is a huge drawbac=
k as it prevents stateful temporary lambdas from being passed as callbacks.=
</p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"dt">void</span> foo(<span class=3D"bu">std::</sp=
an>function<<span class=3D"dt">void</span>()> f);
<span class=3D"dt">int</span> main()
{
<span class=3D"dt">int</span> x =3D <span class=3D"dv">0</span>;
foo(<span class=3D"bu">std::</span>ref([&x]{ ++x; }); <span class=
=3D"co">// does not compile</span>
}</code></pre></div>
<div class=3D"inline-link">
<p><a href=3D"https://godbolt.org/g/DPQ7ku"><em>(on godbolt.org)</em></a></=
p>
</div>
<p>The code above doesn't compile, as <code>std::ref</code> only accepts no=
n-<code>const</code> lvalue references <em>(additionally, <code>std::cref</=
code> is explicitly deleted for rvalue references)</em>. Avoiding the use o=
f <code>std::ref</code> breaks the guarantee that <code>f</code> won't allo=
cate or throw an exception on construction.</p></li>
<li><p><code>std::function</code> is harder for compilers to optimize compa=
red to the proposed <code>function_ref</code>. This is true due to various =
reasons:</p>
<ul>
<li><p><code>std::function</code> can allocate and/or throw exceptions on c=
onstruction and/or assigment.</p></li>
<li><p><code>std::function</code> might use SBO, which could require an add=
itional branch during construction/assignment, make inlining more difficult=
, and unnecessarily increase memory usage.</p></li>
</ul>
<p>Rough benchmarks comparing the generated assembly of a <em><code>std::fu=
nction</code> parameter</em> and a <em><code>function_ref</code> parameter<=
/em> against a <em>template parameter</em> show that:</p>
<ul>
<li><p><code>std::function</code>, on average, generates approximately 5x m=
ore assembly than a template parameter.</p></li>
<li><p><code>function_ref</code>, on average, generates approximately 1.5x =
more assembly than a template parameter.</p></li>
</ul>
<p>A description of the benchmarking techniques used and the full results c=
an be found on my article <em>"passing functions to functions"</em> <a href=
=3D"https://vittorioromeo.info/Misc/fnview4.html#fn1" class=3D"footnoteRef"=
id=3D"fnref1"><sup>1</sup></a>.</p></li>
</ol>
<h2 id=3D"synopsis">Synopsis</h2>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">namespace</span> std
{
<span class=3D"kw">template</span> <<span class=3D"kw">typename</spa=
n>>
<span class=3D"kw">class</span> function_ref; <span class=3D"co">/* und=
efined */</span>
<span class=3D"kw">template</span> <<span class=3D"kw">typename</spa=
n> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">class</span> function_ref<R(Args...)>
{
<span class=3D"kw">public</span>:
<span class=3D"kw">constexpr</span> function_ref() <span class=3D"k=
w">noexcept</span>;
<span class=3D"kw">constexpr</span> function_ref(<span class=3D"bu"=
>std::</span>nullptr_t) <span class=3D"kw">noexcept</span>;
<span class=3D"kw">constexpr</span> function_ref(<span class=3D"at"=
>const</span> function_ref&) <span class=3D"kw">noexcept</span>;
<span class=3D"kw">template</span> <<span class=3D"kw">typename<=
/span> F>
<span class=3D"kw">constexpr</span> function_ref(F&&) <span=
class=3D"kw">noexcept</span>;
<span class=3D"kw">constexpr</span> function_ref& <span class=
=3D"kw">operator</span>=3D(<span class=3D"at">const</span> function_ref&=
;) <span class=3D"kw">noexcept</span>;
<span class=3D"kw">constexpr</span> function_ref& <span class=
=3D"kw">operator</span>=3D(<span class=3D"bu">std::</span>nullptr_t) <span =
class=3D"kw">noexcept</span>;
<span class=3D"kw">template</span> <<span class=3D"kw">typename<=
/span> F>
<span class=3D"kw">constexpr</span> function_ref& <span class=
=3D"kw">operator</span>=3D(F&&) <span class=3D"kw">noexcept</span>;
<span class=3D"kw">constexpr</span> <span class=3D"dt">void</span> =
swap(function_ref&);
<span class=3D"kw">constexpr</span> <span class=3D"kw">explicit</sp=
an> <span class=3D"kw">operator</span> <span class=3D"dt">bool</span>() <sp=
an class=3D"at">const</span> <span class=3D"kw">noexcept</span>;
R <span class=3D"kw">operator</span>()(Args...) <span class=3D"at">=
const</span>;
};
<span class=3D"kw">template</span> <<span class=3D"kw">typename</spa=
n> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> <span class=3D"dt">void</span> swap=
(function_ref<R(Args...)>&, function_ref<R(Args...)>&);
<span class=3D"kw">template</span> <<span class=3D"kw">typename</spa=
n> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> <span class=3D"dt">bool</span> <spa=
n class=3D"kw">operator</span>=3D=3D(<span class=3D"at">const</span> functi=
on_ref<R(Args...)>&, <span class=3D"bu">std::</span>nullptr_t) <s=
pan class=3D"kw">noexcept</span>;
<span class=3D"kw">template</span> <<span class=3D"kw">typename</spa=
n> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> <span class=3D"dt">bool</span> <spa=
n class=3D"kw">operator</span>=3D=3D(<span class=3D"bu">std::</span>nullptr=
_t, <span class=3D"at">const</span> function_ref<R(Args...)>&) <s=
pan class=3D"kw">noexcept</span>;
<span class=3D"kw">template</span> <<span class=3D"kw">typename</spa=
n> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> <span class=3D"dt">bool</span> <spa=
n class=3D"kw">operator</span>!=3D(<span class=3D"at">const</span> function=
_ref<R(Args...)>&, <span class=3D"bu">std::</span>nullptr_t) <spa=
n class=3D"kw">noexcept</span>;
<span class=3D"kw">template</span> <<span class=3D"kw">typename</spa=
n> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> <span class=3D"dt">bool</span> <spa=
n class=3D"kw">operator</span>!=3D(<span class=3D"bu">std::</span>nullptr_t=
, <span class=3D"at">const</span> function_ref<R(Args...)>&) <spa=
n class=3D"kw">noexcept</span>;
<span class=3D"kw">template</span> <<span class=3D"kw">typename</spa=
n> R, <span class=3D"kw">typename</span>... Args>
function_ref(R (*)(Args...)) -> function_ref<R(Args...)>;
<span class=3D"kw">template</span> <<span class=3D"kw">typename</spa=
n> F>
function_ref(F) -> function_ref<<span class=3D"co">/* deduced if =
possible */</span>>;
}</code></pre></div>
<h2 id=3D"specification">Specification</h2>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> function_ref<R(Args...)>::functio=
n_ref() <span class=3D"kw">noexcept</span>;</code></pre></div>
<ul>
<li><p><em>Effects:</em>: constructs a <code>function_ref</code> referring =
to nothing.</p></li>
<li><p><em>Postconditions:</em> <code>bool(*this) =3D=3D false</code>.</p><=
/li>
</ul>
<p><br></p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> function_ref<R(Args...)>::functio=
n_ref(<span class=3D"bu">std::</span>nullptr_t) <span class=3D"kw">noexcept=
</span>;</code></pre></div>
<ul>
<li><p><em>Effects:</em>: constructs a <code>function_ref</code> referring =
to nothing.</p></li>
<li><p><em>Postconditions:</em> <code>bool(*this) =3D=3D false</code>.</p><=
/li>
</ul>
<p><br></p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> function_ref<R(Args...)>::functio=
n_ref(<span class=3D"at">const</span> function_ref& rhs) <span class=3D=
"kw">noexcept</span>;</code></pre></div>
<ul>
<li><p><em>Effects:</em>: constructs a <code>function_ref</code> referring =
to the same callable <code>rhs</code> refers to (or to nothing if <code>boo=
l(rhs) =3D=3D false</code>).</p></li>
<li><p><em>Postconditions:</em> <code>bool(*this) =3D=3D bool(rhs)</code>.<=
/p></li>
</ul>
<p><br></p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">template</span> <<span class=3D"kw">typename</span> F=
>
<span class=3D"kw">constexpr</span> function_ref<R(Args...)>::functio=
n_ref(F&& f) <span class=3D"kw">noexcept</span>;</code></pre></div>
<ul>
<li><p><em>Requires:</em>: This function shall not participate in overload =
resolution unless <code>std::is_same_v<std::decay_t<F>, function_r=
ef> =3D=3D false && std::is_invocable_v<F&&, R, Args.=
...></code>.</p></li>
<li><p><em>Effects:</em>: constructs a <code>function_ref</code> referring =
to <code>f</code>.</p></li>
<li><p><em>Postconditions:</em> <code>bool(*this) =3D=3D true</code>.</p></=
li>
</ul>
<p><br></p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> function_ref& function_ref<R(Arg=
s...)>::<span class=3D"kw">operator</span>=3D(<span class=3D"at">const</=
span> function_ref& rhs) <span class=3D"kw">noexcept</span>;</code></pr=
e></div>
<ul>
<li><p><em>Effects:</em>: <code>*this</code> refers to the same callable <c=
ode>rhs</code> refers to (or to nothing if <code>bool(rhs) =3D=3D false</co=
de>).</p></li>
<li><p><em>Postconditions:</em> <code>bool(*this) =3D=3D bool(rhs)</code>.<=
/p></li>
<li><p><em>Returns:</em> <code>*this</code>.</p></li>
</ul>
<p><br></p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> function_ref& function_ref<R(Arg=
s...)>::<span class=3D"kw">operator</span>=3D(<span class=3D"bu">std::</=
span>nullptr_t) <span class=3D"kw">noexcept</span>;</code></pre></div>
<ul>
<li><p><em>Effects:</em> <code>*this</code> refers to nothing.</p></li>
<li><p><em>Postconditions:</em> <code>bool(*this) =3D=3D false</code>.</p><=
/li>
<li><p><em>Returns:</em> <code>*this</code>.</p></li>
</ul>
<p><br></p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">template</span> <<span class=3D"kw">typename</span> F=
>
<span class=3D"kw">constexpr</span> function_ref& function_ref<R(Arg=
s...)>::<span class=3D"kw">operator</span>=3D(F&&) <span class=
=3D"kw">noexcept</span>;</code></pre></div>
<ul>
<li><p><em>Requires:</em>: <code>std::is_invocable_v<F&&, R, Arg=
s...></code>.</p></li>
<li><p><em>Effects:</em>: <code>*this</code> refers to <code>f</code>.</p><=
/li>
<li><p><em>Postconditions:</em> <code>bool(*this) =3D=3D true</code>.</p></=
li>
<li><p><em>Returns:</em> <code>*this</code>.</p></li>
</ul>
<p><br></p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> <span class=3D"dt">void</span> function=
_ref<R(Args...)>::swap(function_ref& rhs);</code></pre></div>
<ul>
<li><em>Effects:</em> exchanges the values of <code>*this</code> and <code>=
rhs</code>.</li>
</ul>
<p><br></p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> <span class=3D"kw">explicit</span> func=
tion_ref<R(Args...)>::<span class=3D"kw">operator</span> <span class=
=3D"dt">bool</span>() <span class=3D"at">const</span> <span class=3D"kw">no=
except</span>;</code></pre></div>
<ul>
<li><em>Returns:</em> <code>true</code> if <code>*this</code> is referring =
to something, <code>false</code> otherwise.</li>
</ul>
<p><br></p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> R, <span class=3D"kw">typename</span>... Args>
R function_ref<R(Args...)>::<span class=3D"kw">operator</span>()(Args=
.... xs) <span class=3D"at">const</span>;</code></pre></div>
<ul>
<li><p><em>Requires:</em> <code>bool(*this) =3D=3D true</code>.</p></li>
<li><p><em>Effects:</em> equivalent to <code>return static_cast<R>(st=
d::invoke(f, std::forward<Args>(xs)...));</code>, where <code>f</code=
> is the function object referred to by <code>*this</code>, and <code>F</co=
de> is an alias for <code>decltype(f)</code>.</p></li>
<li><p><em>Returns:</em> the return value of the aforementioned invocation =
of the referred callable.</p></li>
</ul>
<p><br></p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> <span class=3D"dt">void</span> swap(fun=
ction_ref<R(Args...)>& lhs, function_ref<R(Args...)>& r=
hs);</code></pre></div>
<ul>
<li><em>Effects:</em> exchanges the values of <code>lhs</code> and <code>rh=
s</code>.</li>
</ul>
<p><br></p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> <span class=3D"dt">bool</span> <span cl=
ass=3D"kw">operator</span>=3D=3D(<span class=3D"at">const</span> function_r=
ef<R(Args...)>& fv, <span class=3D"bu">std::</span>nullptr_t) <sp=
an class=3D"kw">noexcept</span>;</code></pre></div>
<ul>
<li><em>Returns:</em> <code>false</code> if <code>fv</code> is referring to=
something, <code>true</code> otherwise.</li>
</ul>
<p><br></p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> <span class=3D"dt">bool</span> <span cl=
ass=3D"kw">operator</span>=3D=3D(<span class=3D"bu">std::</span>nullptr_t, =
<span class=3D"at">const</span> function_ref<R(Args...)>& fv) <sp=
an class=3D"kw">noexcept</span>;</code></pre></div>
<ul>
<li><em>Returns:</em> <code>fv =3D=3D nullptr</code>.</li>
</ul>
<p><br></p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> <span class=3D"dt">bool</span> <span cl=
ass=3D"kw">operator</span>!=3D(<span class=3D"at">const</span> function_ref=
<R(Args...)>& fv, <span class=3D"bu">std::</span>nullptr_t) <span=
class=3D"kw">noexcept</span>;</code></pre></div>
<ul>
<li><em>Returns:</em> <code>!(fv =3D=3D nullptr)</code>.</li>
</ul>
<p><br></p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"kw">template</span> <<span class=3D"kw">typen=
ame</span> R, <span class=3D"kw">typename</span>... Args>
<span class=3D"kw">constexpr</span> <span class=3D"dt">bool</span> <span cl=
ass=3D"kw">operator</span>!=3D(<span class=3D"bu">std::</span>nullptr_t fv,=
<span class=3D"at">const</span> function_ref<R(Args...)>&) <span=
class=3D"kw">noexcept</span>;</code></pre></div>
<ul>
<li><em>Returns:</em> <code>!(fv =3D=3D nullptr)</code>.</li>
</ul>
<h2 id=3D"existing-practice">Existing practice</h2>
<p>Many facilities similar to <code>function_ref</code> exist and are widel=
y used in large codebases. Here are some examples:</p>
<ul>
<li><p>The <code>llvm::function_ref</code> <a href=3D"https://vittorioromeo=
..info/Misc/fnview4.html#fn2" class=3D"footnoteRef" id=3D"fnref2"><sup>2</su=
p></a> class template is used throughout LLVM. A quick GitHub search on the=
LLVM organization reports hundreds of usages both in <code>llvm</code> and=
<code>clang</code> <a href=3D"https://vittorioromeo.info/Misc/fnview4.html=
#fn3" class=3D"footnoteRef" id=3D"fnref3"><sup>3</sup></a>.</p></li>
<li><p>Facebook's Folly libraries <a href=3D"https://vittorioromeo.info/Mis=
c/fnview4.html#fn4" class=3D"footnoteRef" id=3D"fnref4"><sup>4</sup></a> pr=
ovide a <code>folly::FunctionRef</code> <a href=3D"https://vittorioromeo.in=
fo/Misc/fnview4.html#fn5" class=3D"footnoteRef" id=3D"fnref5"><sup>5</sup><=
/a> class template. A GitHub search shows that it's used in projects <code>=
proxygen</code> and <code>fbthrift</code> <a href=3D"https://vittorioromeo.=
info/Misc/fnview4.html#fn6" class=3D"footnoteRef" id=3D"fnref6"><sup>6</sup=
></a>.</p></li>
</ul>
<p>Additionally, combining results from GitHub searches <em>(excluding "<co=
de>llvm</code>" and "<code>folly</code>")</em> for "<code>function_ref</cod=
e>" <a href=3D"https://vittorioromeo.info/Misc/fnview4.html#fn7" class=3D"f=
ootnoteRef" id=3D"fnref7"><sup>7</sup></a>, "<code>function_view</code>" <a=
href=3D"https://vittorioromeo.info/Misc/fnview4.html#fn8" class=3D"footnot=
eRef" id=3D"fnref8"><sup>8</sup></a>, "<code>FunctionRef</code>" <a href=3D=
"https://vittorioromeo.info/Misc/fnview4.html#fn9" class=3D"footnoteRef" id=
=3D"fnref9"><sup>9</sup></a>, and "<code>FunctionView</code>" <a href=3D"ht=
tps://vittorioromeo.info/Misc/fnview4.html#fn10" class=3D"footnoteRef" id=
=3D"fnref10"><sup>10</sup></a> roughly shows more than 2800 occurrences.</p=
>
<h2 id=3D"possible-issues">Possible issues</h2>
<p>Accepting temporaries in <code>function_ref</code>'s constructor is extr=
emely useful in the most common use case: using it as a function parameter:=
</p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"dt">void</span> foo(function_ref<<span class=
=3D"dt">void</span>()>);
<span class=3D"dt">int</span> main()
{
foo([]{ });
}</code></pre></div>
<div class=3D"inline-link">
<p><a href=3D"https://wandbox.org/permlink/BPtbPeQtErPGj4X7"><em>(on wandbo=
x.org)</em></a></p>
</div>
<p>The usage shown above is completely safe: the temporary closure generate=
d by the lambda expression is guarantee to live for the entirety of the cal=
l to <code>foo</code>. Unfortunately, this also means that the following co=
de snippet will result in <em>undefined behavior</em>:</p>
<div class=3D"sourceCode"><pre class=3D"sourceCode cpp"><code class=3D"sour=
ceCode cpp"><span class=3D"dt">int</span> main()
{
function_ref<<span class=3D"dt">void</span>()> f{[]{ }};
<span class=3D"co">// ...</span>
f(); <span class=3D"co">// undefined behavior</span>
}</code></pre></div>
<div class=3D"inline-link">
<p><a href=3D"https://wandbox.org/permlink/cQPEX2sKjCQjgIki"><em>(on wandbo=
x.org)</em></a></p>
</div>
<p>The above closure is a temporary whose lifetime ends after the <code>fun=
ction_ref</code> constructor call. The <code>function_ref</code> will store=
an address to a "dead" closure - invoking it will produce undefined behavi=
or <a href=3D"https://vittorioromeo.info/Misc/fnview4.html#fn11" class=3D"f=
ootnoteRef" id=3D"fnref11"><sup>11</sup></a>. As an example, <code>AddressS=
anitizer</code> detects an invalid memory access in this gist <a href=3D"ht=
tps://vittorioromeo.info/Misc/fnview4.html#fn12" class=3D"footnoteRef" id=
=3D"fnref12"><sup>12</sup></a>. Note that this problem is not unique to <co=
de>function_ref</code>: the recently standardized <code>std::string_view</c=
ode> <a href=3D"https://vittorioromeo.info/Misc/fnview4.html#fn13" class=3D=
"footnoteRef" id=3D"fnref13"><sup>13</sup></a> has the same problem <a href=
=3D"https://vittorioromeo.info/Misc/fnview4.html#fn14" class=3D"footnoteRef=
" id=3D"fnref14"><sup>14</sup></a>.</p>
<p>I strongly believe that accepting temporaries is a "necessary evil" for =
both <code>function_ref</code> and <code>std::string_view</code>, as it ena=
bles countless valid use cases. The problem of dangling references has been=
always present in the language - a more general solution like Herb Sutter =
and Neil Macintosh's lifetime tracking <a href=3D"https://vittorioromeo.inf=
o/Misc/fnview4.html#fn15" class=3D"footnoteRef" id=3D"fnref15"><sup>15</sup=
></a> would prevent mistakes without limiting the usefulness of view/refere=
nce classes.</p>
<h2 id=3D"open-questions">Open questions</h2>
<p>Below are some unanswered questions for which I kindly ask guidance from=
members of the commitee and readers of this paper.</p>
<ul>
<li><p><code>function_ref::operator()</code> is not currently marked as <co=
de>constexpr</code> due to implementation issues. I could not figure a way =
to implement a <code>constexpr</code>-friendly <code>operator()</code>. Is =
there any possibility it could be marked as <code>constexpr</code> to incre=
ase the usefulness of <code>function_ref</code>?</p></li>
<li><p><code>function_ref::operator()</code> is qualified as <code>const</c=
ode> and always invokes the referenced <code>Callable</code> with <code>std=
::invoke(f, std::forward<Args>(xs)...)</code>. Should <code>f</code> =
be perfectly-forwarded? Should ref-qualified versions of <code>function_ref=
::operator()</code> that apply the ref qualifier to <code>f</code> be provi=
ded to allow users to invoke the referenced <code>Callable</code>'s potenti=
ally ref-qualified <code>operator()</code> overloads?</p></li>
</ul>
<h2 id=3D"bikeshedding">Bikeshedding</h2>
<p>The name <code>function_ref</code> is subject to bikeshedding. Here are =
some other potential names:</p>
<ul>
<li><p><code>function_view</code></p></li>
<li><p><code>callable_ref</code></p></li>
<li><p><code>callable_view</code></p></li>
<li><p><code>invocable_ref</code></p></li>
<li><p><code>invocable_view</code></p></li>
<li><p><code>fn_view</code></p></li>
<li><p><code>fn_ref</code></p></li>
</ul>
<h2 id=3D"acknowledgments">Acknowledgments</h2>
<p>Thanks to <strong>Eric Niebler</strong> and <strong>Tim van Deurzen</str=
ong> for providing very valuable feedback on earlier drafts of this proposa=
l.</p>
<h2 id=3D"references">References</h2>
<div class=3D"footnotes">
<hr>
<ol>
<li id=3D"fn1"><p><a href=3D"https://vittorioromeo.info/index/blog/passing_=
functions_to_functions.html#benchmark---generated-assembly" class=3D"uri">h=
ttps://vittorioromeo.info/index/blog/passing_functions_to_functions.html#be=
nchmark---generated-assembly</a><a href=3D"https://vittorioromeo.info/Misc/=
fnview4.html#fnref1">=E2=86=A9</a></p></li>
<li id=3D"fn2"><p><a href=3D"http://llvm.org/doxygen/classllvm_1_1function_=
_ref_3_01Ret_07Params_8_8_8_08_4.html" class=3D"uri">http://llvm.org/doxyge=
n/classllvm_1_1function__ref_3_01Ret_07Params_8_8_8_08_4.html</a><a href=3D=
"https://vittorioromeo.info/Misc/fnview4.html#fnref2">=E2=86=A9</a></p></li=
>
<li id=3D"fn3"><p><a href=3D"https://github.com/search?q=3Dorg%3Allvm-mirro=
r+function_ref&type=3DCode">https://github.com/search?q=3Dorg%3Allvm-mi=
rror+function_ref&type=3DCode</a><a href=3D"https://vittorioromeo.info/=
Misc/fnview4.html#fnref3">=E2=86=A9</a></p></li>
<li id=3D"fn4"><p><a href=3D"https://github.com/facebook/folly" class=3D"ur=
i">https://github.com/facebook/folly</a><a href=3D"https://vittorioromeo.in=
fo/Misc/fnview4.html#fnref4">=E2=86=A9</a></p></li>
<li id=3D"fn5"><p><a href=3D"https://github.com/facebook/folly/blob/master/=
folly/Function.h#L743-L824" class=3D"uri">https://github.com/facebook/folly=
/blob/master/folly/Function.h#L743-L824</a><a href=3D"https://vittorioromeo=
..info/Misc/fnview4.html#fnref5">=E2=86=A9</a></p></li>
<li id=3D"fn6"><p><a href=3D"https://github.com/search?q=3Dorg%3Afacebook+F=
unctionRef&type=3DCode">https://github.com/search?q=3Dorg%3Afacebook+Fu=
nctionRef&type=3DCode</a><a href=3D"https://vittorioromeo.info/Misc/fnv=
iew4.html#fnref6">=E2=86=A9</a></p></li>
<li id=3D"fn7"><p><a href=3D"https://github.com/search?utf8=3D%E2%9C%93&=
;q=3Dfunction_ref+AND+NOT+llvm+AND+NOT+folly+language%3AC%2B%2B&type=3D=
Code">https://github.com/search?utf8=3D%E2%9C%93&q=3Dfunction_ref+AND+N=
OT+llvm+AND+NOT+folly+language%3AC%2B%2B&type=3DCode</a><a href=3D"http=
s://vittorioromeo.info/Misc/fnview4.html#fnref7">=E2=86=A9</a></p></li>
<li id=3D"fn8"><p><a href=3D"https://github.com/search?utf8=3D%E2%9C%93&=
;q=3Dfunction_view+AND+NOT+llvm+AND+NOT+folly+language%3AC%2B%2B&type=
=3DCode">https://github.com/search?utf8=3D%E2%9C%93&q=3Dfunction_view+A=
ND+NOT+llvm+AND+NOT+folly+language%3AC%2B%2B&type=3DCode</a><a href=3D"=
https://vittorioromeo.info/Misc/fnview4.html#fnref8">=E2=86=A9</a></p></li>
<li id=3D"fn9"><p><a href=3D"https://github.com/search?utf8=3D%E2%9C%93&=
;q=3Dfunctionref+AND+NOT+llvm+AND+NOT+folly+language%3AC%2B%2B&type=3DC=
ode">https://github.com/search?utf8=3D%E2%9C%93&q=3Dfunctionref+AND+NOT=
+llvm+AND+NOT+folly+language%3AC%2B%2B&type=3DCode</a><a href=3D"https:=
//vittorioromeo.info/Misc/fnview4.html#fnref9">=E2=86=A9</a></p></li>
<li id=3D"fn10"><p><a href=3D"https://github.com/search?utf8=3D%E2%9C%93&am=
p;q=3Dfunctionview+AND+NOT+llvm+AND+NOT+folly+language%3AC%2B%2B&type=
=3DCode">https://github.com/search?utf8=3D%E2%9C%93&q=3Dfunctionview+AN=
D+NOT+llvm+AND+NOT+folly+language%3AC%2B%2B&type=3DCode</a><a href=3D"h=
ttps://vittorioromeo.info/Misc/fnview4.html#fnref10">=E2=86=A9</a></p></li>
<li id=3D"fn11"><p><a href=3D"http://foonathan.net/blog/2017/01/20/function=
-ref-implementation.html" class=3D"uri">http://foonathan.net/blog/2017/01/2=
0/function-ref-implementation.html</a><a href=3D"https://vittorioromeo.info=
/Misc/fnview4.html#fnref11">=E2=86=A9</a></p></li>
<li id=3D"fn12"><p><a href=3D"https://gist.github.com/SuperV1234/a41eb1c825=
bfbb43f595b13bd4ea99c3" class=3D"uri">https://gist.github.com/SuperV1234/a4=
1eb1c825bfbb43f595b13bd4ea99c3</a><a href=3D"https://vittorioromeo.info/Mis=
c/fnview4.html#fnref12">=E2=86=A9</a></p></li>
<li id=3D"fn13"><p><a href=3D"http://www.open-std.org/jtc1/sc22/wg21/docs/p=
apers/2013/n3762.html" class=3D"uri">http://www.open-std.org/jtc1/sc22/wg21=
/docs/papers/2013/n3762.html</a><a href=3D"https://vittorioromeo.info/Misc/=
fnview4.html#fnref13">=E2=86=A9</a></p></li>
<li id=3D"fn14"><p><a href=3D"http://foonathan.net/blog/2017/03/22/string_v=
iew-temporary.html" class=3D"uri">http://foonathan.net/blog/2017/03/22/stri=
ng_view-temporary.html</a><a href=3D"https://vittorioromeo.info/Misc/fnview=
4.html#fnref14">=E2=86=A9</a></p></li>
<li id=3D"fn15"><p><a href=3D"https://github.com/isocpp/CppCoreGuidelines/b=
lob/master/docs/Lifetimes%20I%20and%20II%20-%20v0.9.1.pdf">https://github.c=
om/isocpp/CppCoreGuidelines/blob/master/docs/Lifetimes%20I%20and%20II%20-%2=
0v0.9.1.pdf</a><a href=3D"https://vittorioromeo.info/Misc/fnview4.html#fnre=
f15">=E2=86=A9</a></p></li>
</ol>
</div>
</body></html>
------=_Part_239_898686295.1500135949376--
.