<!DOCTYPE html>

<html lang="en">

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="mobile-web-app-capable" content="yes">
    <title>
        function_ref: a type-erased callable reference - HackMD
    </title>
    <link rel="icon" type="image/png" href="https://hackmd.io/favicon.png">
    <link rel="apple-touch-icon" href="https://hackmd.io/apple-touch-icon.png">

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css" integrity="sha256-3iu9jgsy9TpTwXKb7bNQzqWekRX7pPK+2OLj3R922fo=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/octicons/3.5.0/octicons.min.css" integrity="sha256-QiWfLIsCT02Sdwkogf6YMiQlj4NE84MKkzEMkZnMGdg=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/themes/prism.min.css" integrity="sha256-vtR0hSWRc3Tb26iuN2oZHt3KRUomwTufNIf5/4oeCyg=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@hackmd/emojify.js@2.1.0/dist/css/basic/emojify.min.css" integrity="sha256-UOrvMOsSDSrW6szVLe8ZDZezBxh5IoIfgTwdNDgTjiU=" crossorigin="anonymous" />
    <style>
        @import url(https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500,500i|Source+Code+Pro:300,400,500|Source+Sans+Pro:300,300i,400,400i,600,600i|Source+Serif+Pro&subset=latin-ext);.hljs{display:block;background:#fff;padding:.5em;color:#333;overflow-x:auto}.hljs-comment,.hljs-meta{color:#969896}.hljs-emphasis,.hljs-quote,.hljs-string,.hljs-strong,.hljs-template-variable,.hljs-variable{color:#df5000}.hljs-keyword,.hljs-selector-tag,.hljs-type{color:#a71d5d}.hljs-attribute,.hljs-bullet,.hljs-literal,.hljs-number,.hljs-symbol{color:#0086b3}.hljs-built_in,.hljs-builtin-name{color:#005cc5}.hljs-name,.hljs-section{color:#63a35c}.hljs-tag{color:#333}.hljs-attr,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-title{color:#795da3}.hljs-addition{color:#55a532;background-color:#eaffea}.hljs-deletion{color:#bd2c00;background-color:#ffecec}.hljs-link{text-decoration:underline}.markdown-body{font-size:16px;line-height:1.5;word-wrap:break-word}.markdown-body:after,.markdown-body:before{display:table;content:""}.markdown-body:after{clear:both}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body .absent{color:#c00}.markdown-body .anchor{float:left;padding-right:4px;margin-left:-20px;line-height:1}.markdown-body .anchor:focus{outline:none}.markdown-body blockquote,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-top:0;margin-bottom:16px}.markdown-body hr{height:.25em;padding:0;margin:24px 0;background-color:#e7e7e7;border:0}.markdown-body blockquote{font-size:16px;padding:0 1em;color:#777;border-left:.25em solid #ddd}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body kbd,.popover kbd{display:inline-block;padding:3px 5px;font-size:11px;line-height:10px;color:#555;vertical-align:middle;background-color:#fcfcfc;border:1px solid #ccc;border-bottom-color:#bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb}.markdown-body .loweralpha{list-style-type:lower-alpha}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{margin-top:24px;margin-bottom:16px;font-weight:600;line-height:1.25}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{color:#000;vertical-align:middle;visibility:hidden}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{visibility:visible}.markdown-body h1 code,.markdown-body h1 tt,.markdown-body h2 code,.markdown-body h2 tt,.markdown-body h3 code,.markdown-body h3 tt,.markdown-body h4 code,.markdown-body h4 tt,.markdown-body h5 code,.markdown-body h5 tt,.markdown-body h6 code,.markdown-body h6 tt{font-size:inherit}.markdown-body h1{font-size:2em}.markdown-body h1,.markdown-body h2{padding-bottom:.3em;border-bottom:1px solid #eee}.markdown-body h2{font-size:1.5em}.markdown-body h3{font-size:1.25em}.markdown-body h4{font-size:1em}.markdown-body h5{font-size:.875em}.markdown-body h6{font-size:.85em;color:#777}.markdown-body ol,.markdown-body ul{padding-left:2em}.markdown-body ol.no-list,.markdown-body ul.no-list{padding:0;list-style-type:none}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:0;margin-bottom:0}.markdown-body li>p{margin-top:16px}.markdown-body li+li{padding-top:.25em}.markdown-body dl{padding:0}.markdown-body dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:700}.markdown-body dl dd{padding:0 16px;margin-bottom:16px}.markdown-body table{display:block;width:100%;overflow:auto;word-break:normal;word-break:keep-all}.markdown-body table th{font-weight:700}.markdown-body table td,.markdown-body table th{padding:6px 13px;border:1px solid #ddd}.markdown-body table tr{background-color:#fff;border-top:1px solid #ccc}.markdown-body table tr:nth-child(2n){background-color:#f8f8f8}.markdown-body img{max-width:100%;box-sizing:content-box;background-color:#fff}.markdown-body img[align=right]{padding-left:20px}.markdown-body img[align=left]{padding-right:20px}.markdown-body .emoji{max-width:none;vertical-align:text-top;background-color:transparent}.markdown-body span.frame{display:block;overflow:hidden}.markdown-body span.frame>span{display:block;float:left;width:auto;padding:7px;margin:13px 0 0;overflow:hidden;border:1px solid #ddd}.markdown-body span.frame span img{display:block;float:left}.markdown-body span.frame span span{display:block;padding:5px 0 0;clear:both;color:#333}.markdown-body span.align-center{display:block;overflow:hidden;clear:both}.markdown-body span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown-body span.align-center span img{margin:0 auto;text-align:center}.markdown-body span.align-right{display:block;overflow:hidden;clear:both}.markdown-body span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown-body span.align-right span img{margin:0;text-align:right}.markdown-body span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown-body span.float-left span{margin:13px 0 0}.markdown-body span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown-body span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown-body code,.markdown-body tt{padding:0;padding-top:.2em;padding-bottom:.2em;margin:0;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px}.markdown-body code:after,.markdown-body code:before,.markdown-body tt:after,.markdown-body tt:before{letter-spacing:-.2em;content:"\00a0"}.markdown-body code br,.markdown-body tt br{display:none}.markdown-body del code{text-decoration:inherit}.markdown-body pre{word-wrap:normal}.markdown-body pre>code{padding:0;margin:0;font-size:100%;word-break:normal;white-space:pre;background:transparent;border:0}.markdown-body .highlight{margin-bottom:16px}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body .highlight pre,.markdown-body pre{padding:16px;overflow:auto;font-size:85%;line-height:1.45;background-color:#f7f7f7;border-radius:3px}.markdown-body pre code,.markdown-body pre tt{display:inline;max-width:auto;padding:0;margin:0;overflow:visible;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}.markdown-body pre code:after,.markdown-body pre code:before,.markdown-body pre tt:after,.markdown-body pre tt:before{content:normal}.markdown-body .csv-data td,.markdown-body .csv-data th{padding:5px;overflow:hidden;font-size:12px;line-height:1;text-align:left;white-space:nowrap}.markdown-body .csv-data .blob-line-num{padding:10px 8px 9px;text-align:right;background:#fff;border:0}.markdown-body .csv-data tr{border-top:0}.markdown-body .csv-data th{font-weight:700;background:#f8f8f8;border-top:0}.news .alert .markdown-body blockquote{padding:0 0 0 40px;border:0 none}.activity-tab .news .alert .commits,.activity-tab .news .markdown-body blockquote{padding-left:0}.task-list-item{list-style-type:none}.task-list-item label{font-weight:400}.task-list-item.enabled label{cursor:pointer}.task-list-item+.task-list-item{margin-top:3px}.task-list-item-checkbox{float:left;margin:.31em 0 .2em -1.3em!important;vertical-align:middle;cursor:default!important}.markdown-body{padding-top:40px;padding-bottom:40px;max-width:758px;overflow:visible!important;position:relative}.markdown-body .emoji{vertical-align:top}.markdown-body pre{border:inherit!important}.markdown-body code{color:inherit!important}.markdown-body pre code .wrapper{display:-moz-inline-flex;display:-ms-inline-flex;display:-o-inline-flex;display:inline-flex}.markdown-body pre code .gutter{float:left;overflow:hidden;-webkit-user-select:none;user-select:none}.markdown-body pre code .gutter.linenumber{text-align:right;position:relative;display:inline-block;cursor:default;z-index:4;padding:0 8px 0 0;min-width:20px;box-sizing:content-box;color:#afafaf!important;border-right:3px solid #6ce26c!important}.markdown-body pre code .gutter.linenumber>span:before{content:attr(data-linenumber)}.markdown-body pre code .code{float:left;margin:0 0 0 16px}.markdown-body .gist .line-numbers{border-left:none;border-top:none;border-bottom:none}.markdown-body .gist .line-data{border:none}.markdown-body .gist table{border-spacing:0;border-collapse:inherit!important}.markdown-body code[data-gist-id]{background:none;padding:0}.markdown-body code[data-gist-id]:after,.markdown-body code[data-gist-id]:before{content:""}.markdown-body code[data-gist-id] .blob-num{border:unset}.markdown-body code[data-gist-id] table{overflow:unset;margin-bottom:unset}.markdown-body code[data-gist-id] table tr{background:unset}.markdown-body[dir=rtl] pre{direction:ltr}.markdown-body[dir=rtl] code{direction:ltr;unicode-bidi:embed}.markdown-body .alert>p:last-child{margin-bottom:0}.markdown-body pre.abc,.markdown-body pre.flow-chart,.markdown-body pre.graphviz,.markdown-body pre.mermaid,.markdown-body pre.sequence-diagram,.markdown-body pre.vega{text-align:center;background-color:inherit;border-radius:0;white-space:inherit;overflow:visible}.markdown-body pre.abc>code,.markdown-body pre.flow-chart>code,.markdown-body pre.graphviz>code,.markdown-body pre.mermaid>code,.markdown-body pre.sequence-diagram>code,.markdown-body pre.vega>code{text-align:left}.markdown-body pre.abc>svg,.markdown-body pre.flow-chart>svg,.markdown-body pre.graphviz>svg,.markdown-body pre.mermaid>svg,.markdown-body pre.sequence-diagram>svg,.markdown-body pre.vega>svg{max-width:100%;height:100%}.markdown-body pre>code.wrap{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.markdown-body .alert>p:last-child,.markdown-body .alert>ul:last-child{margin-bottom:0}.markdown-body summary{display:list-item}.markdown-body summary:focus{outline:none}.markdown-body details summary{cursor:pointer}.markdown-body details:not([open])>:not(summary){display:none}.markdown-body figure{margin:1em 40px}.markdown-body .mark,.markdown-body mark{background-color:#fff1a7}.vimeo,.youtube{cursor:pointer;display:table;text-align:center;background-position:50%;background-repeat:no-repeat;background-size:contain;background-color:#000;overflow:hidden}.vimeo,.youtube{position:relative;width:100%}.youtube{padding-bottom:56.25%}.vimeo img{width:100%;object-fit:contain;z-index:0}.youtube img{object-fit:cover;z-index:0}.vimeo iframe,.youtube iframe,.youtube img{width:100%;height:100%;position:absolute;top:0;left:0}.vimeo iframe,.youtube iframe{vertical-align:middle;z-index:1}.vimeo .icon,.youtube .icon{position:absolute;height:auto;width:auto;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff;opacity:.3;transition:opacity .2s;z-index:0}.vimeo:hover .icon,.youtube:hover .icon{opacity:.6;transition:opacity .2s}.slideshare .inner,.speakerdeck .inner{position:relative;width:100%}.slideshare .inner iframe,.speakerdeck .inner iframe{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%}.figma{display:table;position:relative;width:100%;padding-bottom:56.25%}.figma iframe{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%;border:1px solid #eee}.MJX_Assistive_MathML{display:none}#MathJax_Message{z-index:1000!important}.ui-infobar{position:relative;z-index:2;max-width:760px;margin:25px auto -25px;color:#777}.toc .invisable-node{list-style-type:none}.ui-toc{position:fixed;bottom:20px;z-index:998}.ui-toc.both-mode{margin-left:8px}.ui-toc.both-mode .ui-toc-label{height:40px;padding:10px 4px;border-top-left-radius:0;border-bottom-left-radius:0}.ui-toc-label{background-color:#e6e6e6;border:none;color:#868686;transition:opacity .2s}.ui-toc .open .ui-toc-label{opacity:1;color:#fff;transition:opacity .2s}.ui-toc-label:focus{opacity:.3;background-color:#ccc;color:#000}.ui-toc-label:hover{opacity:1;background-color:#ccc;transition:opacity .2s}.ui-toc-dropdown{margin-top:20px;margin-bottom:20px;padding-left:10px;padding-right:10px;max-width:45vw;width:25vw;max-height:70vh;overflow:auto;text-align:inherit}.ui-toc-dropdown>.toc{max-height:calc(70vh - 100px);overflow:auto}.ui-toc-dropdown[dir=rtl] .nav{padding-right:0;letter-spacing:.0029em}.ui-toc-dropdown a{overflow:hidden;text-overflow:ellipsis;white-space:pre}.ui-toc-dropdown .nav>li>a{display:block;padding:4px 20px;font-size:13px;font-weight:500;color:#767676}.ui-toc-dropdown .nav>li:first-child:last-child>ul,.ui-toc-dropdown .toc.expand ul{display:block}.ui-toc-dropdown .nav>li>a:focus,.ui-toc-dropdown .nav>li>a:hover{padding-left:19px;color:#000;text-decoration:none;background-color:transparent;border-left:1px solid #000}.ui-toc-dropdown[dir=rtl] .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav>li>a:hover{padding-right:19px;border-left:none;border-right:1px solid #000}.ui-toc-dropdown .nav>.active:focus>a,.ui-toc-dropdown .nav>.active:hover>a,.ui-toc-dropdown .nav>.active>a{padding-left:18px;font-weight:700;color:#000;background-color:transparent;border-left:2px solid #000}.ui-toc-dropdown[dir=rtl] .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav>.active>a{padding-right:18px;border-left:none;border-right:2px solid #000}.ui-toc-dropdown .nav .nav{display:none;padding-bottom:10px}.ui-toc-dropdown .nav>.active>ul{display:block}.ui-toc-dropdown .nav .nav>li>a{padding-top:1px;padding-bottom:1px;padding-left:30px;font-size:12px;font-weight:400}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a{padding-right:30px}.ui-toc-dropdown .nav .nav>li>ul>li>a{padding-top:1px;padding-bottom:1px;padding-left:40px;font-size:12px;font-weight:400}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a{padding-right:40px}.ui-toc-dropdown .nav .nav>li>a:focus,.ui-toc-dropdown .nav .nav>li>a:hover{padding-left:29px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:hover{padding-right:29px}.ui-toc-dropdown .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown .nav .nav>li>ul>li>a:hover{padding-left:39px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:hover{padding-right:39px}.ui-toc-dropdown .nav .nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>a{padding-left:28px;font-weight:500}.ui-toc-dropdown[dir=rtl] .nav .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>a{padding-right:28px}.ui-toc-dropdown .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active>a{padding-left:38px;font-weight:500}.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active>a{padding-right:38px}.markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,sans-serif}html[lang^=ja] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,ＭＳ\ ゴシック,sans-serif}html[lang=zh-tw] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}html .markdown-body[lang^=ja]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,ＭＳ\ ゴシック,sans-serif}html .markdown-body[lang=zh-tw]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html .markdown-body[lang=zh-cn]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}html[lang^=ja] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Meiryo UI,MS PGothic,ＭＳ\ Ｐゴシック,sans-serif}html[lang=zh-tw] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Microsoft JhengHei UI,微軟正黑UI,sans-serif}html[lang=zh-cn] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Microsoft YaHei UI,微软雅黑UI,sans-serif}html .ui-toc-dropdown[lang^=ja]{font-family:Source Sans Pro,Helvetica,Arial,Meiryo UI,MS PGothic,ＭＳ\ Ｐゴシック,sans-serif}html .ui-toc-dropdown[lang=zh-tw]{font-family:Source Sans Pro,Helvetica,Arial,Microsoft JhengHei UI,微軟正黑UI,sans-serif}html .ui-toc-dropdown[lang=zh-cn]{font-family:Source Sans Pro,Helvetica,Arial,Microsoft YaHei UI,微软雅黑UI,sans-serif}.ui-affix-toc{position:fixed;top:0;max-width:15vw;max-height:70vh;overflow:auto}.back-to-top,.expand-toggle,.go-to-bottom{display:block;padding:4px 10px;margin-top:10px;margin-left:10px;font-size:12px;font-weight:500;color:#999}.back-to-top:focus,.back-to-top:hover,.expand-toggle:focus,.expand-toggle:hover,.go-to-bottom:focus,.go-to-bottom:hover{color:#563d7c;text-decoration:none}.back-to-top,.go-to-bottom{margin-top:0}.ui-user-icon{width:20px;height:20px;display:block;border-radius:50%;margin-top:2px;margin-bottom:2px;margin-right:5px;background-position:50%;background-repeat:no-repeat;background-size:cover}.ui-user-icon.small{width:18px;height:18px;display:inline-block;vertical-align:middle;margin:0 0 .2em}.ui-infobar>small>span{line-height:22px}.ui-infobar>small .dropdown{display:inline-block}.ui-infobar>small .dropdown a:focus,.ui-infobar>small .dropdown a:hover{text-decoration:none}.ui-more-info{color:#888;cursor:pointer;vertical-align:middle}.ui-more-info .fa{font-size:16px}.ui-connectedGithub,.ui-published-note{color:#888}.ui-connectedGithub{line-height:23px;white-space:nowrap}.ui-connectedGithub a.file-path{color:#888;text-decoration:none;padding-left:22px}.ui-connectedGithub a.file-path:active,.ui-connectedGithub a.file-path:hover{color:#888;text-decoration:underline}.ui-connectedGithub .fa{font-size:20px}.ui-published-note .fa{font-size:20px;vertical-align:top}.unselectable{-webkit-user-select:none;-o-user-select:none;user-select:none}.selectable{-webkit-user-select:text;-o-user-select:text;user-select:text}@media print{blockquote,div,img,pre,table{page-break-inside:avoid!important}a[href]:after{font-size:12px!important}}.markdown-body.slides{position:relative;z-index:1;color:#222}.markdown-body.slides:before{content:"";display:block;position:absolute;top:0;left:0;right:0;bottom:0;z-index:-1;background-color:currentColor;box-shadow:0 0 0 50vw}.markdown-body.slides section[data-markdown]{position:relative;margin-bottom:1.5em;background-color:#fff;text-align:center}.markdown-body.slides section[data-markdown] code{text-align:left}.markdown-body.slides section[data-markdown]:before{content:"";display:block;padding-bottom:56.23%}.markdown-body.slides section[data-markdown]>div:first-child{position:absolute;top:50%;left:1em;right:1em;transform:translateY(-50%);max-height:100%;overflow:hidden}.markdown-body.slides section[data-markdown]>ul{display:inline-block}.markdown-body.slides>section>section+section:after{content:"";position:absolute;top:-1.5em;right:1em;height:1.5em;border:3px solid #777}.site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,sans-serif}html[lang^=ja] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,ＭＳ\ ゴシック,sans-serif}html[lang=zh-tw] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}body{font-smoothing:subpixel-antialiased!important;-webkit-font-smoothing:subpixel-antialiased!important;-moz-osx-font-smoothing:auto!important;text-shadow:0 0 1em transparent,1px 1px 1.2px rgba(0,0,0,.004);-webkit-overflow-scrolling:touch;letter-spacing:.025em;font-family:Source Sans Pro,Helvetica,Arial,sans-serif}html[lang^=ja] body{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,ＭＳ\ ゴシック,sans-serif}html[lang=zh-tw] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}abbr[data-original-title],abbr[title]{cursor:help}body.modal-open{overflow-y:auto;padding-right:0!important}
    </style>
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
    	<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js" integrity="sha256-3Jy/GbSLrg0o9y5Z5n1uw0qxZECH7C6OQpVBgNFYa0g=" crossorigin="anonymous"></script>
    	<script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js" integrity="sha256-g6iAfvZp+nDQ2TdTR/VVKJf3bGro4ub5fvWSWVRi2NE=" crossorigin="anonymous"></script>
		<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-shim.min.js" integrity="sha256-8E4Is26QH0bD52WoQpcB+R/tcWQtpzlCojrybUd7Mxo=" crossorigin="anonymous"></script>
    <![endif]-->
</head>

<body>
    <div id="doc" class="markdown-body container-fluid comment-enabled" data-hard-breaks="false"><style>
ins { background-color: #CCFFCC }
s { background-color: #FFCACA }
blockquote { color: inherit !important }
</style><table><tbody>
<tr><th>Doc. no.:</th>    <td>P0792R6</td></tr>
<tr><th>Date:</th>        <td>2022-01-17</td></tr>
<tr><th>Audience:</th>    <td>LEWG, LWG</td></tr>
<tr><th>Reply-to:</th>    <td>Vittorio Romeo &lt;vittorio.romeo@outlook.com&gt;<br>
Zhihao Yuan &lt;zy@miator.net&gt;<br>
Jarrad Waterloo &lt;descender76@gmail.com&gt;</td></tr>
</tbody></table><h1 id="function_ref-a-type-erased-callable-reference" data-id="function_ref-a-type-erased-callable-reference"><a class="anchor hidden-xs" href="#function_ref-a-type-erased-callable-reference" title="function_ref-a-type-erased-callable-reference"><span class="octicon octicon-link"></span></a><code>function_ref</code><span>: a type-erased callable reference</span></h1><h2 id="Table-of-contents" data-id="Table-of-contents"><a class="anchor hidden-xs" href="#Table-of-contents" title="Table-of-contents"><span class="octicon octicon-link"></span></a><span>Table of contents</span></h2><p><span class="toc"><ul>
<li><a href="#function_ref-a-type-erased-callable-reference" title="function_ref: a type-erased callable reference">function_ref: a type-erased callable reference</a><ul>
<li><a href="#Table-of-contents" title="Table of contents">Table of contents</a></li>
<li><a href="#Changelog" title="Changelog">Changelog</a><ul>
<li><a href="#R6" title="R6">R6</a></li>
<li><a href="#R5" title="R5">R5</a></li>
<li><a href="#R4" title="R4">R4</a></li>
<li><a href="#R3" title="R3">R3</a></li>
<li><a href="#R2" title="R2">R2</a></li>
<li><a href="#R1" title="R1">R1</a></li>
</ul>
</li>
<li><a href="#Abstract" title="Abstract">Abstract</a></li>
<li><a href="#Design-considerations" title="Design considerations">Design considerations</a><ul>
<li><a href="#Question-1" title="Question 1">Question 1</a></li>
<li><a href="#Question-2" title="Question 2">Question 2</a></li>
<li><a href="#Question-3" title="Question 3">Question 3</a></li>
</ul>
</li>
<li><a href="#Discussion" title="Discussion">Discussion</a><ul>
<li><a href="#Is-stdfunction_ref-“parameter-only”" title="Is std::function_ref “parameter-only?”">Is std::function_ref “parameter-only?”</a></li>
<li><a href="#Is-this-only-a-lifetime-issue" title="Is this only a lifetime issue?">Is this only a lifetime issue?</a></li>
<li><a href="#Is-this-an-issue-or-non-issue" title="Is this an issue or non-issue?">Is this an issue or non-issue?</a></li>
</ul>
</li>
<li><a href="#Rationale" title="Rationale">Rationale</a><ul>
<li><a href="#Background-knowledge" title="Background knowledge">Background knowledge</a></li>
<li><a href="#Theory" title="Theory">Theory</a></li>
<li><a href="#Test" title="Test">Test</a></li>
<li><a href="#On-pointer-to-member" title="On pointer-to-member">On pointer-to-member</a></li>
</ul>
</li>
<li><a href="#Wording" title="Wording">Wording</a></li>
<li><a href="#Feature-test-macro" title="Feature test macro">Feature test macro</a></li>
<li><a href="#Implementation-Experience" title="Implementation Experience">Implementation Experience</a></li>
<li><a href="#Acknowledgments" title="Acknowledgments">Acknowledgments</a></li>
<li><a href="#References" title="References">References</a></li>
</ul>
</li>
</ul>
</span></p><h2 id="Changelog" data-id="Changelog"><a class="anchor hidden-xs" href="#Changelog" title="Changelog"><span class="octicon octicon-link"></span></a><span>Changelog</span></h2><h3 id="R6" data-id="R6"><a class="anchor hidden-xs" href="#R6" title="R6"><span class="octicon octicon-link"></span></a><span>R6</span></h3><ul>
<li><span>Avoid double-wrapping existing references to callables;</span></li>
<li><span>Reworked the wording to follow the latest standardese;</span></li>
<li><span>Applied changes requested by LWG (2020-07);</span></li>
<li><span>Removed a deduction guide that is incompatible with explicit object parameters.</span></li>
</ul><h3 id="R5" data-id="R5"><a class="anchor hidden-xs" href="#R5" title="R5"><span class="octicon octicon-link"></span></a><span>R5</span></h3><ul>
<li><span>Removed “qualifiers” from </span><code>operator()</code><span> specification (typo);</span></li>
</ul><h3 id="R4" data-id="R4"><a class="anchor hidden-xs" href="#R4" title="R4"><span class="octicon octicon-link"></span></a><span>R4</span></h3><ul>
<li><span>Removed </span><code>constexpr</code><span> due to implementation concerns;</span></li>
<li><span>Explicitly say that the type is trivially copyable;</span></li>
<li><span>Added brief before synopsis;</span></li>
<li><span>Reworded specification following P1369.</span></li>
</ul><h3 id="R3" data-id="R3"><a class="anchor hidden-xs" href="#R3" title="R3"><span class="octicon octicon-link"></span></a><span>R3</span></h3><ul>
<li><span>Constructing or assigning from </span><code>std::function</code><span> no longer has a precondition;</span></li>
<li><code>function_ref::operator()</code><span> is now unconditionally </span><code>const</code><span>-qualified.</span></li>
</ul><h3 id="R2" data-id="R2"><a class="anchor hidden-xs" href="#R2" title="R2"><span class="octicon octicon-link"></span></a><span>R2</span></h3><ul>
<li><span>Made copy constructor and assignment operator </span><code>= default</code><span>;</span></li>
<li><span>Added </span><em><span>exposition only</span></em><span> data members.</span></li>
</ul><h3 id="R1" data-id="R1"><a class="anchor hidden-xs" href="#R1" title="R1"><span class="octicon octicon-link"></span></a><span>R1</span></h3><ul>
<li><span>Removed empty state, comparisons with </span><code>nullptr</code><span>, and default constructor;</span></li>
<li><span>Added support for </span><code>noexcept</code><span> and </span><code>const</code><span>-qualified function signatures;</span></li>
<li><span>Added deduction guides similar to </span><code>std::function</code><span>;</span></li>
<li><span>Added example implementation;</span></li>
<li><span>Added feature test macro;</span></li>
<li><span>Removed </span><code>noexcept</code><span> from constructor and assignment operator.</span></li>
</ul><h2 id="Abstract" data-id="Abstract"><a class="anchor hidden-xs" href="#Abstract" title="Abstract"><span class="octicon octicon-link"></span></a><span>Abstract</span></h2><p><span>This paper proposes the addition of </span><code>function_ref&lt;R(Args...)&gt;</code><span>, a </span><em><span>vocabulary type</span></em><span> with reference semantics for passing entities to call, to the standard library.</span></p><h2 id="Design-considerations" data-id="Design-considerations"><a class="anchor hidden-xs" href="#Design-considerations" title="Design-considerations"><span class="octicon octicon-link"></span></a><span>Design considerations</span></h2><p><span>This paper went through LEWG at R5, with a number of consensus reached and applied to the wording:</span></p><ol>
<li><span>Do not provide </span><code>target()</code><span> or </span><code>target_type</code><span>;</span></li>
<li><span>Do not provide </span><code>operator bool</code><span>, default constructor, or comparison with </span><code>nullptr</code><span>;</span></li>
<li><span>Provide </span><code>R(Args...) noexcept</code><span> specializations;</span></li>
<li><span>Provide </span><code>R(Args...) const</code><span> specializations;</span></li>
<li><span>Require the target entity to be </span><em><span>Lvalue-Callable</span></em><span>;</span></li>
<li><span>Make </span><code>operator()</code><span> unconditionally </span><code>const</code><span>;</span></li>
<li><span>Choose </span><code>function_ref</code><span> as the right name.</span></li>
</ol><p><span>One design question remains not fully understood by many: how should a function, a function pointer, or a pointer-to-member initialize </span><code>function_ref</code><span>? The sixth revision of the paper aims to provide full background and dive deep into that question.</span></p><h3 id="Question-1" data-id="Question-1"><a class="anchor hidden-xs" href="#Question-1" title="Question-1"><span class="octicon octicon-link"></span></a><span>Question 1</span></h3><p><span>There has been a concern on whether</span></p><pre><code class="cpp hljs"><span class="token keyword">int</span> <span class="token function">f</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

function_ref fr <span class="token operator">=</span> <span class="token operator">&amp;</span>f<span class="token punctuation">;</span>
<span class="token function">fr</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p><span>creates a </span><code>function_ref</code><span> object that points to a temporary function pointer and results in undefined behavior when called on the last line.</span></p><p><span>LEWG believes that </span><code>fr</code><span> should not be dangling here; it should store the function pointer. This is also </span><a href="https://github.com/facebook/folly/blob/main/folly/Function.h" target="_blank" rel="noopener"><code>folly::FunctionRef</code></a><span>, </span><a href="https://github.com/bminor/binutils-gdb/blob/master/gdbsupport/function-view.h" target="_blank" rel="noopener"><code>gdb::function_view</code></a><span>, and </span><a href="https://github.com/foonathan/type_safe/blob/main/include/type_safe/reference.hpp" target="_blank" rel="noopener"><code>type_safe::function_ref</code></a><span> (by Jonathan Müller)'s behavior.</span></p><p><span>P0792R5</span><sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup><span> believes that </span><code>fr</code><span> should be dangling here because the function pointer here is a prvalue callable object, and the nature of the problem is indifferent from </span><code>string_view</code><sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup><span>. This is </span><a href="https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/ADT/STLExtras.h" target="_blank" rel="noopener"><code>llvm::function_ref</code></a><span>, </span><a href="https://github.com/TartanLlama/function_ref/blob/master/include/tl/function_ref.hpp" target="_blank" rel="noopener"><code>tl::function_ref</code></a><span> (by Sy Brand), and </span><a href="https://github.com/vittorioromeo/Experiments/blob/master/function_ref.cpp" target="_blank" rel="noopener"><span>P0792R5 sample implementation</span></a><span>’s behavior.</span></p><p><span>LWG inferred and recognized the 2</span><sup><span>nd</span></sup><span> behavior from P0792R5 wording.</span></p><p><strong><span>This paper (R6) supports the 1</span><sup><span>st</span></sup><span> behavior.</span></strong></p><h3 id="Question-2" data-id="Question-2"><a class="anchor hidden-xs" href="#Question-2" title="Question-2"><span class="octicon octicon-link"></span></a><span>Question 2</span></h3><p><span>The question above leads to the follow-up question: should </span><code>fr</code><span> be dangling if assigned a function?</span></p><pre><code class="cpp hljs"><span class="token keyword">int</span> <span class="token function">f</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

function_ref fr <span class="token operator">=</span> f<span class="token punctuation">;</span>
<span class="token function">fr</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p><span>LEWG believes that this case is indifferent to </span><a href="#Question-1"><span>Question 1</span></a><span> and should work. This is </span><a href="https://github.com/facebook/folly/blob/main/folly/Function.h" target="_blank" rel="noopener"><code>folly::FunctionRef</code></a><span>, </span><a href="https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/ADT/STLExtras.h" target="_blank" rel="noopener"><code>llvm::function_ref</code></a><span>, </span><a href="https://github.com/TartanLlama/function_ref/blob/master/include/tl/function_ref.hpp" target="_blank" rel="noopener"><code>tl::function_ref</code></a><span>, and </span><a href="https://github.com/vittorioromeo/Experiments/blob/master/function_ref.cpp" target="_blank" rel="noopener"><span>P0792R5 sample implementation</span></a><span>’s behavior assuming the C++ implementation supports converting a function pointer to an object pointer type or vice versa. This is also </span><a href="https://github.com/bminor/binutils-gdb/blob/master/gdbsupport/function-view.h" target="_blank" rel="noopener"><code>gdb::function_view</code></a><span> and </span><a href="https://github.com/foonathan/type_safe/blob/main/include/type_safe/reference.hpp" target="_blank" rel="noopener"><code>type_safe::function_ref</code></a><span>’s behavior because their implementation involves a union.</span><sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup></p><p><span>P0792R5’s design is that, </span><code>function_ref</code><span> references nothing but </span><em><span>callable objects</span></em><span> </span><a href="https://eel.is/c++draft/func.def#4" target="_blank" rel="noopener"><span>[func.def]</span></a><span>. A function is not an object, so there is nothing we can reference. The function should decay into a function pointer prvalue, and we are back to </span><a href="#Question-1"><span>Question 1</span></a><span>. No known implementation supports this behavior.</span></p><p><span>LWG inferred and recognized the 1</span><sup><span>st</span></sup><span> behavior from P0792R5 wording.</span></p><p><strong><span>This paper (R6) supports the 1</span><sup><span>st</span></sup><span> behavior.</span></strong></p><h3 id="Question-3" data-id="Question-3"><a class="anchor hidden-xs" href="#Question-3" title="Question-3"><span class="octicon octicon-link"></span></a><span>Question 3</span></h3><p><span>The last question is about pointer to members.</span></p><pre><code class="cpp hljs"><span class="token keyword">struct</span> <span class="token class-name">A</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> <span class="token function">mf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> a<span class="token punctuation">;</span>

function_ref fr <span class="token operator">=</span> <span class="token operator">&amp;</span>A<span class="token operator">::</span>mf<span class="token punctuation">;</span>
<span class="token function">fr</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p><span>Does the above have defined behavior?</span></p><p><span>LEWG made a poll and gave permission to “fully support the </span><code>Callable</code><span> concept at the potential cost of </span><code>sizeof(function_ref) &gt;= sizeof(void(*)()) * 2</code><span>,” </span><span class="mathjax"><span class="MathJax_Preview" style="color: inherit;"></span><span id="MathJax-Element-8-Frame" class="mjx-chtml MathJax_CHTML" tabindex="0" style="font-size: 113%; position: relative;" data-mathml="<math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;><mn>6</mn><mrow class=&quot;MJX-TeXAtom-ORD&quot;><mo>/</mo></mrow><mn>4</mn><mrow class=&quot;MJX-TeXAtom-ORD&quot;><mo>/</mo></mrow><mn>0</mn><mrow class=&quot;MJX-TeXAtom-ORD&quot;><mo>/</mo></mrow><mn>0</mn><mrow class=&quot;MJX-TeXAtom-ORD&quot;><mo>/</mo></mrow><mn>0</mn></math>" role="presentation"><span id="MJXc-Node-40" class="mjx-math" aria-hidden="true"><span id="MJXc-Node-41" class="mjx-mrow"><span id="MJXc-Node-42" class="mjx-mn"><span class="mjx-char MJXc-TeX-main-R" style="padding-top: 0.39em; padding-bottom: 0.39em;">6</span></span><span id="MJXc-Node-43" class="mjx-texatom"><span id="MJXc-Node-44" class="mjx-mrow"><span id="MJXc-Node-45" class="mjx-mo"><span class="mjx-char MJXc-TeX-main-R" style="padding-top: 0.445em; padding-bottom: 0.611em;">/</span></span></span></span><span id="MJXc-Node-46" class="mjx-mn"><span class="mjx-char MJXc-TeX-main-R" style="padding-top: 0.39em; padding-bottom: 0.335em;">4</span></span><span id="MJXc-Node-47" class="mjx-texatom"><span id="MJXc-Node-48" class="mjx-mrow"><span id="MJXc-Node-49" class="mjx-mo"><span class="mjx-char MJXc-TeX-main-R" style="padding-top: 0.445em; padding-bottom: 0.611em;">/</span></span></span></span><span id="MJXc-Node-50" class="mjx-mn"><span class="mjx-char MJXc-TeX-main-R" style="padding-top: 0.39em; padding-bottom: 0.39em;">0</span></span><span id="MJXc-Node-51" class="mjx-texatom"><span id="MJXc-Node-52" class="mjx-mrow"><span id="MJXc-Node-53" class="mjx-mo"><span class="mjx-char MJXc-TeX-main-R" style="padding-top: 0.445em; padding-bottom: 0.611em;">/</span></span></span></span><span id="MJXc-Node-54" class="mjx-mn"><span class="mjx-char MJXc-TeX-main-R" style="padding-top: 0.39em; padding-bottom: 0.39em;">0</span></span><span id="MJXc-Node-55" class="mjx-texatom"><span id="MJXc-Node-56" class="mjx-mrow"><span id="MJXc-Node-57" class="mjx-mo"><span class="mjx-char MJXc-TeX-main-R" style="padding-top: 0.445em; padding-bottom: 0.611em;">/</span></span></span></span><span id="MJXc-Node-58" class="mjx-mn"><span class="mjx-char MJXc-TeX-main-R" style="padding-top: 0.39em; padding-bottom: 0.39em;">0</span></span></span></span><span class="MJX_Assistive_MathML" role="presentation"><math xmlns="http://www.w3.org/1998/Math/MathML"><mn>6</mn><mrow class="MJX-TeXAtom-ORD"><mo>/</mo></mrow><mn>4</mn><mrow class="MJX-TeXAtom-ORD"><mo>/</mo></mrow><mn>0</mn><mrow class="MJX-TeXAtom-ORD"><mo>/</mo></mrow><mn>0</mn><mrow class="MJX-TeXAtom-ORD"><mo>/</mo></mrow><mn>0</mn></math></span></span><script type="math/tex" id="MathJax-Element-8">6/4/0/0/0</script></span><span> in 2018-6. This implies that an implementation should expand its union to store the pointer to member functions. No known implementation supports this behavior.</span></p><p data-original-title="" title=""><span>P0792R5 emphasizes that pointer-to-member objects are </span><em><span>callable</span></em><span>. Therefore we should point to those objects and deal with the potential dangling issue with tools. All the implementations mentioned above except </span><a href="https://github.com/foonathan/type_safe/blob/main/include/type_safe/reference.hpp" target="_blank" rel="noopener"><code>type_safe::function_ref</code></a><span> give this behavior.</span></p><p><a href="https://github.com/foonathan/type_safe/blob/main/include/type_safe/reference.hpp" target="_blank" rel="noopener"><code>type_safe::function_ref</code></a><span> does not support initializing from a pointer-to-member and suggests the users to opt-in the 2</span><sup><span>nd</span></sup><span> behavior with </span><code>std::mem_fn(&amp;A::mf)</code><span>.</span></p><p><span>LWG recognized the 2</span><sup><span>nd</span></sup><span> behavior while reviewing P0792R5 and generally agreed that a two-pointer </span><code>function_ref</code><span> is fat enough.</span></p><p><strong><span>This is an open question in R6 of the paper, even though we bring in new information.</span></strong><span> We will discuss all options and their defenses.</span></p><h2 id="Discussion" data-id="Discussion"><a class="anchor hidden-xs" href="#Discussion" title="Discussion"><span class="octicon octicon-link"></span></a><span>Discussion</span></h2><h3 id="Is-stdfunction_ref-“parameter-only”" data-id="Is-stdfunction_ref-“parameter-only”"><a class="anchor hidden-xs" href="#Is-stdfunction_ref-“parameter-only”" title="Is-stdfunction_ref-“parameter-only”"><span class="octicon octicon-link"></span></a><span>Is </span><code>std::function_ref</code><span> “parameter-only?”</span></h3><p><span>Some people believe that </span><code>std::function_ref</code><span> only needs to support being used as a parameter.</span><sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup><span> In a typical scenario,</span></p><pre><code class="cpp hljs"><span class="token keyword">auto</span> <span class="token function">retry</span><span class="token punctuation">(</span>function_ref<span class="token operator">&lt;</span>optional<span class="token operator">&lt;</span>payload<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">&gt;</span> action<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p><span>there is no lifetime issue and all the three questions above do not matter:</span></p><pre><code class="cpp hljs"><span class="token keyword">auto</span> result <span class="token operator">=</span> <span class="token function">retry</span><span class="token punctuation">(</span>download<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// always safe</span>
</code></pre><p><span>However, even if the users use </span><code>function_ref</code><span> only as parameters initially, it’s not uncommon to evolve the API by grouping parameters into structures, then structures become classes with constructors… And the end-users of the library will be tempted to prepare the parameter set before calling into the API:</span></p><pre><code class="cpp hljs">retry_options <span class="token function">opt</span><span class="token punctuation">(</span>download<span class="token punctuation">,</span> <span class="token number">1.5</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">auto</span> result <span class="token operator">=</span> <span class="token function">retry</span><span class="token punctuation">(</span>opt<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// safe...?</span>
</code></pre><p><span>If </span><code>download</code><span> is a function, the answer to </span><a href="#Question-1"><span>Question 1</span></a><span> will now decide whether the code has well-defined behavior.</span></p><h3 id="Is-this-only-a-lifetime-issue" data-id="Is-this-only-a-lifetime-issue"><a class="anchor hidden-xs" href="#Is-this-only-a-lifetime-issue" title="Is-this-only-a-lifetime-issue"><span class="octicon octicon-link"></span></a><span>Is this only a lifetime issue?</span></h3><p><span>The three questions we show above are often deemed “lifetime issues.” Being a lifetime issue in C++ implies a misuse and a workaround. Moreover, users can look for lifetime issues with tools such as lifetime checkers, sanitizers, etc.</span></p><p><span>However, although we demonstrate the problem as a lifetime issue, the solutions we chose can inevitably impact the semantics of </span><code>function_ref</code><span>.</span></p><p><span>In the following line,</span></p><pre><code class="cpp hljs">retry_options <span class="token function">opt</span><span class="token punctuation">(</span>p<span class="token punctuation">,</span> <span class="token number">1.5</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p><code>p</code><span> is a pointer to function. It’s an lvalue, so there is no lifetime issue. But if we go with the 2</span><sup><span>nd</span></sup><span> behavior when answering </span><a href="#Question-2"><span>Question 2</span></a><span>, a latter code that rebinds </span><code>p</code><span> to something else</span></p><pre><code class="cpp hljs">p <span class="token operator">=</span> winhttp_download<span class="token punctuation">;</span>
</code></pre><p><span>will replace </span><code>opt</code><span>’s behavior.</span></p><p><span>One might argue that this behavior difference wouldn’t be visible if </span><code>function_ref</code><span> were used only in parameter lists. However, this is not true either. If that function is a coroutine, the caller side can rebind </span><code>p</code><span> and ultimately change the behavior of the copy after the coroutine resumes.</span></p><h3 id="Is-this-an-issue-or-non-issue" data-id="Is-this-an-issue-or-non-issue"><a class="anchor hidden-xs" href="#Is-this-an-issue-or-non-issue" title="Is-this-an-issue-or-non-issue"><span class="octicon octicon-link"></span></a><span>Is this an issue or non-issue?</span></h3><p><span>One might argue that what is stated so far are all corner cases. For example, lambda expressions create rvalue closures, so they always outlive </span><code>function_ref</code><span> immediately if you initialize </span><code>function_ref</code><span> variables with them. So what motivates us to guarantee more for functions and even function pointers?</span></p><p><span>The situation is that no implementation in the real world dangles in all three cases. Inevitably, some guarantees have become features in practice. For example,</span></p><pre><code class="cpp hljs"><span class="token keyword">struct</span> <span class="token class-name">retry_options</span>
<span class="token punctuation">{</span>
    <span class="token function">retry_options</span><span class="token punctuation">(</span><span class="token comment">/* ... */</span><span class="token punctuation">)</span> <span class="token comment">/* ... */</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>

    function_ref<span class="token operator">&lt;</span>sig<span class="token operator">&gt;</span> callback <span class="token operator">=</span> fn_fail<span class="token punctuation">;</span>
    seconds gap<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><p><span>is a natural way to replace the default behavior with a specific one that reports failure. In addition, this style will become necessary after upgrading to </span><code>std::function_ref</code><span> as it has no default constructor.</span></p><p><span>In short, we’re standardizing existing practice and can’t leave “production” behavior implementation-defined. We expect the committee to give firm answers to these questions.</span></p><h2 id="Rationale" data-id="Rationale"><a class="anchor hidden-xs" href="#Rationale" title="Rationale"><span class="octicon octicon-link"></span></a><span>Rationale</span></h2><h3 id="Background-knowledge" data-id="Background-knowledge"><a class="anchor hidden-xs" href="#Background-knowledge" title="Background-knowledge"><span class="octicon octicon-link"></span></a><span>Background knowledge</span></h3><p><span>We have always treated </span><code>function_ref</code><span> as a </span><code>std::function</code><span> or </span><code>std::move_only_function</code><span> with reference semantics. But when applying this understanding, we worked out certain aspects of </span><code>function_ref</code><span> based on existing jargons, while these jargons reflect a contrived view of </span><code>std::move_only_function</code><span>.</span></p><blockquote>
<p><span>The </span><code>move_only_function</code><span> class template provides polymorphic wrappers that generalize the notion of a callable object.</span>
<span>– </span><a href="https://eel.is/c++draft/func.wrap.move.class#1" target="_blank" rel="noopener"><span>[func.wrap.move.class]/1</span></a></p>
</blockquote><blockquote>
<p><span>A </span><em><span>callable object</span></em><span> is an object of a callable type.</span>
<span>– </span><a href="https://eel.is/c++draft/func.def#4" target="_blank" rel="noopener"><span>[func.def]/4</span></a></p>
</blockquote><blockquote>
<p><span>A </span><em><span>callable type</span></em><span> is a function object type or a pointer to member.</span>
<span>– </span><a href="https://eel.is/c++draft/func.def#3" target="_blank" rel="noopener"><span>[func.def]/3</span></a></p>
</blockquote><p><span>In other words, from the library’s point of view, function is not “callable.” A function, reference to function, or reference to a callable object, can be used in </span><code>std::invoke</code><span>, and they satisfy the new </span><code>invocable</code><span> concept, but </span><code>std::move_only_function</code><span> is unaware of their existence. </span><code>move_only_function</code><span> stores callable objects (i.e., target objects). As long as something is to initialize that object, </span><code>move_only_function</code><span> is happy to accept it.</span></p><p><span>So defining </span><code>function_ref</code><span> as a “reference to a callable” leads to a problem: what do we do when there is no “callable object,” invent one?</span></p><p><span>But </span><code>function_ref</code><span> had never meant to initialize any target object by treating the argument to </span><code>function_ref(F&amp;&amp;)</code><span> as an initializer. To </span><code>move_only_function</code><span>’s constructor, its argument is an initializer; if the argument is an object, the entity to call is always a different object – a distinct copy of the argument. To </span><code>function_ref</code><span>’s constructor, its argument </span><strong><span>is</span></strong><span> the entity to call.</span></p><p><span>I think this is a fundamental difference between </span><code>function_ref</code><span> and </span><code>move_only_function</code><span>. In the two </span><code>(F&amp;&amp;)</code><span> constructors, </span><code>F&amp;&amp;</code><span> in </span><code>move_only_function(F&amp;&amp;)</code><span> is to forward value, while in </span><code>function_ref(F&amp;&amp;)</code><span>, </span><code>F&amp;&amp;</code><span>'s role is to pass an identity so that we can call the entity that owns the identity via the reference. In my definition, </span><code>F&amp;&amp;</code><span> is a </span><strong><span>callable reference</span></strong><span>.</span></p><h3 id="Theory" data-id="Theory"><a class="anchor hidden-xs" href="#Theory" title="Theory"><span class="octicon octicon-link"></span></a><span>Theory</span></h3><p><span>By saying something “models after a pointer,” I mean the identity of such thing is irrelevant to the identity of the entity to reach after dereferencing. In C++, the “identity” here can be an address as nothing is relocatable in the abstract machine. By saying something “models after a reference,” I mean it is similar to a pointer but lets you use that thing in place of the dereferenced entity.</span></p><p><span>When saying something is a “callable reference,” I mean that thing models after a reference and is invocable. For example, an object pointer is not a callable reference, but a function pointer is. A reference to a function (e.g., </span><code>void (&amp;)(int)</code><span>) is naturally a callable reference. </span><code>reference_wrapper&lt;T&gt;</code><span> is also a callable reference if </span><code>T</code><span> is invocable.</span></p><p><code>function_ref&lt;S&gt;</code><span> is a callable reference as well. And I believe that when initializing </span><code>function_ref</code><span> from another callable reference, the </span><code>function_ref</code><span> object should bind to the entity behind the other callable reference. Such a callable reference needs to be type-passing since the conversion only can work as if we have both the identity and the type to the referenced entity.</span></p><h3 id="Test" data-id="Test"><a class="anchor hidden-xs" href="#Test" title="Test"><span class="octicon octicon-link"></span></a><span>Test</span></h3><p><span>What should happen when a </span><code>function_ref&lt;S&gt;</code><span> object is initialized from or binds to another object of the same type?</span></p><p><span>Both are type-erased callable references. By saying something is type-erasing, we mean there exists a type </span><span class="mathjax"><span class="MathJax_Preview" style="color: inherit;"></span><span id="MathJax-Element-9-Frame" class="mjx-chtml MathJax_CHTML" tabindex="0" style="font-size: 113%; position: relative;" data-mathml="<math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;><mi>C</mi></math>" role="presentation"><span id="MJXc-Node-59" class="mjx-math" aria-hidden="true"><span id="MJXc-Node-60" class="mjx-mrow"><span id="MJXc-Node-61" class="mjx-mi"><span class="mjx-char MJXc-TeX-math-I" style="padding-top: 0.501em; padding-bottom: 0.279em; padding-right: 0.045em;">C</span></span></span></span><span class="MJX_Assistive_MathML" role="presentation"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>C</mi></math></span></span><script type="math/tex" id="MathJax-Element-9">C</script></span><span> that can be used in place of </span><span class="mathjax"><span class="MathJax_Preview" style="color: inherit;"></span><span id="MathJax-Element-10-Frame" class="mjx-chtml MathJax_CHTML" tabindex="0" style="font-size: 113%; position: relative;" data-mathml="<math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;><mi>A</mi></math>" role="presentation"><span id="MJXc-Node-62" class="mjx-math" aria-hidden="true"><span id="MJXc-Node-63" class="mjx-mrow"><span id="MJXc-Node-64" class="mjx-mi"><span class="mjx-char MJXc-TeX-math-I" style="padding-top: 0.501em; padding-bottom: 0.279em;">A</span></span></span></span><span class="MJX_Assistive_MathML" role="presentation"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>A</mi></math></span></span><script type="math/tex" id="MathJax-Element-10">A</script></span><span> and </span><span class="mathjax"><span class="MathJax_Preview" style="color: inherit;"></span><span id="MathJax-Element-11-Frame" class="mjx-chtml MathJax_CHTML" tabindex="0" style="font-size: 113%; position: relative;" data-mathml="<math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;><mi>B</mi></math>" role="presentation"><span id="MJXc-Node-65" class="mjx-math" aria-hidden="true"><span id="MJXc-Node-66" class="mjx-mrow"><span id="MJXc-Node-67" class="mjx-mi"><span class="mjx-char MJXc-TeX-math-I" style="padding-top: 0.445em; padding-bottom: 0.279em;">B</span></span></span></span><span class="MJX_Assistive_MathML" role="presentation"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>B</mi></math></span></span><script type="math/tex" id="MathJax-Element-11">B</script></span><span> without forming a dependent expression. Type-passing means that substituting </span><span class="mathjax"><span class="MathJax_Preview" style="color: inherit;"></span><span id="MathJax-Element-12-Frame" class="mjx-chtml MathJax_CHTML" tabindex="0" style="font-size: 113%; position: relative;" data-mathml="<math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;><mi>A</mi></math>" role="presentation"><span id="MJXc-Node-68" class="mjx-math" aria-hidden="true"><span id="MJXc-Node-69" class="mjx-mrow"><span id="MJXc-Node-70" class="mjx-mi"><span class="mjx-char MJXc-TeX-math-I" style="padding-top: 0.501em; padding-bottom: 0.279em;">A</span></span></span></span><span class="MJX_Assistive_MathML" role="presentation"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>A</mi></math></span></span><script type="math/tex" id="MathJax-Element-12">A</script></span><span> with </span><span class="mathjax"><span class="MathJax_Preview" style="color: inherit;"></span><span id="MathJax-Element-13-Frame" class="mjx-chtml MathJax_CHTML" tabindex="0" style="font-size: 113%; position: relative;" data-mathml="<math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;><mi>B</mi></math>" role="presentation"><span id="MJXc-Node-71" class="mjx-math" aria-hidden="true"><span id="MJXc-Node-72" class="mjx-mrow"><span id="MJXc-Node-73" class="mjx-mi"><span class="mjx-char MJXc-TeX-math-I" style="padding-top: 0.445em; padding-bottom: 0.279em;">B</span></span></span></span><span class="MJX_Assistive_MathML" role="presentation"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>B</mi></math></span></span><script type="math/tex" id="MathJax-Element-13">B</script></span><span> changes the type of the expression. But when copy-constructing</span><code>function_ref</code><span>, the arguments are of the same type. So you can say that an expression to initialize </span><code>function_ref&lt;S&gt;</code><span> is dependent on </span><code>function_ref&lt;S&gt;</code><span>. The source type is equivalent to a type-passing callable reference, so we duplicate the internal states to make the two objects behave as if they are bound to the same entity.</span></p><blockquote>
<p><span>Why bring up the suggestion to unwrap </span><code>reference_wrapper</code><span> again?</span></p>
</blockquote><p><span>Doing so fixes an issue: if initializing an object of </span><code>function_ref&lt;R(Args...) const&gt;</code><span> from </span><code>std::ref(obj)</code><span> given a modifiable </span><code>obj</code><span>, the </span><code>const</code><span> in the signature is not propagated to </span><code>obj</code><span>. It is the opposite behavior compared to the following:</span></p><pre><code class="cpp hljs"><span class="token keyword">struct</span> <span class="token class-name">A</span>
<span class="token punctuation">{</span>
    <span class="token keyword">int</span> <span class="token keyword">operator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span><span class="token punctuation">;</span>  <span class="token comment">// 1</span>
    <span class="token keyword">int</span> <span class="token keyword">operator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token comment">// 2</span>
<span class="token punctuation">}</span> obj<span class="token punctuation">;</span>

function_ref<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">const</span><span class="token operator">&gt;</span> fr <span class="token operator">=</span> obj<span class="token punctuation">;</span>
<span class="token function">fr</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// calls 1</span>
</code></pre><p><span>If </span><code>obj</code><span> were </span><code>const</code><span>, </span><code>std::ref(obj)</code><span> produces </span><code>reference_wrapper&lt;T const&gt;</code><span>, which calls #2. This tells us </span><code>std::ref</code><span> had never meant to “ensure” that an object is modifiable. By not creating </span><code>function_ref</code><span> on top of </span><code>reference_wrapper</code><span>, we prevent dangling, avoid object pointers that point to function pointers once more, and preserve </span><code>reference_wrapper</code><span>’s design logic.</span></p><h3 id="On-pointer-to-member" data-id="On-pointer-to-member"><a class="anchor hidden-xs" href="#On-pointer-to-member" title="On-pointer-to-member"><span class="octicon octicon-link"></span></a><span>On pointer-to-member</span></h3><p><span>We are back to the </span><a href="#Question-3"><span>open question</span></a><span>. Pointer-to-members are hard to categorize. You could imagine that a pointer-to-member is some callable reference, but the entity it references does not exist in the language.</span></p><p><span>I think all of the following arguments make sense:</span></p><ol>
<li><span>Because their referenced entities do not exist in the language, the code that initializes </span><code>function_ref</code><span> from a pointer-to-member should be ill-formed.</span></li>
<li><span>Their referenced entities do not exist</span><span class="mathjax"><span class="MathJax_Preview" style="color: inherit;"></span><span id="MathJax-Element-18-Frame" class="mjx-chtml MathJax_CHTML" tabindex="0" style="font-size: 113%; position: relative;" data-mathml="<math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;><mspace width=&quot;thickmathspace&quot; /><mo stretchy=&quot;false&quot;>&amp;#x27F9;</mo><mspace width=&quot;thickmathspace&quot; /></math>" role="presentation"><span id="MJXc-Node-94" class="mjx-math" aria-hidden="true"><span id="MJXc-Node-95" class="mjx-mrow"><span id="MJXc-Node-96" class="mjx-mspace" style="width: 0.278em; height: 0px;"></span><span id="MJXc-Node-97" class="mjx-mo"><span class="mjx-char MJXc-TeX-main-R" style="padding-top: 0.224em; padding-bottom: 0.39em;">⟹</span></span><span id="MJXc-Node-98" class="mjx-mspace" style="width: 0.278em; height: 0px;"></span></span></span><span class="MJX_Assistive_MathML" role="presentation"><math xmlns="http://www.w3.org/1998/Math/MathML"><mspace width="thickmathspace"></mspace><mo stretchy="false">⟹</mo><mspace width="thickmathspace"></mspace></math></span></span><script type="math/tex" id="MathJax-Element-18">\implies</script></span><span>they are not callable references. Therefore they should be treated as callable objects, even though they might be prvalues.</span></li>
<li><span>Themselves should be treated as callable references even though they refer to hypothetical things. </span><code>function_ref</code><span>’s internal pointer may be an object pointer, a function pointer, and a pointer-to-member.</span></li>
</ol><p><span>Meanwhile, there are other ways to use pointer-to-members in </span><code>function_ref</code><span>. </span><code>std::mem_fn(&amp;A::mf)</code><span> is an option. Another option is </span><code>nontype&lt;&amp;A::mf&gt;</code><span> from P2511</span><sup class="footnote-ref"><a href="#fn5" id="fnref5">[5]</a></sup><span>:</span></p><pre><code class="cpp hljs"><span class="token keyword">struct</span> <span class="token class-name">A</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> <span class="token function">mf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> a<span class="token punctuation">;</span>

function_ref<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token punctuation">(</span>A<span class="token operator">&amp;</span><span class="token punctuation">)</span><span class="token operator">&gt;</span> fr <span class="token operator">=</span> nontype<span class="token operator">&lt;</span><span class="token operator">&amp;</span>A<span class="token operator">::</span>mf<span class="token operator">&gt;</span><span class="token punctuation">;</span>  <span class="token comment">// not dangling</span>
<span class="token function">fr</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><p><span>Interestingly, this makes </span><code>function_ref</code><span> comparable to a GCC feature that converts PMF constants to function pointers</span><sup class="footnote-ref"><a href="#fn6" id="fnref6">[6]</a></sup><span>, except that the underlying implementation involves a thunk.</span></p><h2 id="Wording" data-id="Wording"><a class="anchor hidden-xs" href="#Wording" title="Wording"><span class="octicon octicon-link"></span></a><span>Wording</span></h2><p><span>The wording is relative to N4901.</span></p><p><span>Add the template to </span><a href="https://eel.is/c++draft/functional.syn" target="_blank" rel="noopener"><span>[functional.syn]</span></a><span>, header </span><code>&lt;functional&gt;</code><span> synopsis:</span></p><blockquote>
<p><span>[…]</span></p>
</blockquote><pre>  <i>// [func.wrap.move], move only wrapper</i>
  template&lt;class... S&gt; class move_only_function;        <i>// not defined</i>
  template&lt;class R, class... ArgTypes&gt;
    class move_only_function&lt;R(ArgTypes...) <i>cv ref</i> noexcept(<i>noex</i>)&gt;; <i>// see below</i>

  <ins><i>// [func.wrap.ref], non-owning wrapper</i>
  template&lt;class S&gt; class function_ref;                 <i>// not defined</i>
  template&lt;class R, class... ArgTypes&gt;
    class function_ref&lt;R(ArgTypes...) <i>cv</i> noexcept(<i>noex</i>)&gt;;           <i>// see below</i></ins>
</pre><blockquote>
<p><span>[…]</span></p>
</blockquote><p><span>Create a new section “Non-owning wrapper”, </span><code>[func.wrap.ref]</code><span> with the following:</span></p><blockquote>
<h2 id="General" data-id="General"><a class="anchor hidden-xs" href="#General" title="General"><span class="octicon octicon-link"></span></a><span>General</span></h2>
<p><span>[func.wrap.ref.general]</span></p>
<p><span>The header provides partial specializations of </span><code>function_ref</code><span> for each combination of the possible replacements of the placeholders </span><em><span>cv</span></em><span> and </span><em><span>noex</span></em><span> where:</span></p>
<ul>
<li><em><span>cv</span></em><span> is either </span><code>const</code><span> or empty.</span></li>
<li><em><span>noex</span></em><span> is either </span><code>true</code><span> or </span><code>false</code><span>.</span></li>
</ul>
<p><span>An object of class </span><code>function_ref&lt;S&gt;</code><span> stores a pointer to thunk and a bound argument entity. A </span><em><span>thunk</span></em><span> is a function where a pointer to that function is a perfect forwarding call wrapper </span><a href="https://eel.is/c++draft/func.def" target="_blank" rel="noopener"><span>[func.def]</span></a><span>. The bound argument is of an implementation-defined type to represent a pointer to object value, a pointer to function value, or a null pointer value.</span></p>
<p><code>function_ref&lt;S&gt;</code><span> is a trivially copyable type </span><a href="https://eel.is/c++draft/basic.types" target="_blank" rel="noopener"><span>[basic.types]</span></a><span>.</span></p>
<p><span>Within this subclause, </span><code>call_args</code><span> is an argument pack used in a function call expression </span><a href="https://eel.is/c++draft/expr.call" target="_blank" rel="noopener"><span>[expr.call]</span></a><span> of </span><code>*this</code><span>, and </span><code>val</code><span> is the value that the bound argument stores.</span></p>
</blockquote><br><blockquote>
<h3 id="Class-template-function_ref" data-id="Class-template-function_ref"><a class="anchor hidden-xs" href="#Class-template-function_ref" title="Class-template-function_ref"><span class="octicon octicon-link"></span></a><span>Class template </span><code>function_ref</code></h3>
<p><span>[func.wrap.ref.class]</span></p>
</blockquote><pre>namespace std
{
  template&lt;class S&gt; class function_ref;       <i>// not defined</i>

  template&lt;class R, class... ArgTypes&gt;
  class function_ref&lt;R(ArgTypes...) <i>cv</i> noexcept(<i>noex</i>)&gt;
  {
  public:
    <i>// [func.wrap.ref.ctor], constructors and assignment operator</i>
    template&lt;class F&gt; function_ref(F*) noexcept;
    template&lt;class F&gt; function_ref(F&amp;&amp;) noexcept;

    function_ref(const function_ref&amp;) noexcept = default;
    function_ref&amp; operator=(const function_ref&amp;) noexcept = default;

    <i>// [func.wrap.ref.inv], invocation</i>
    R operator()(ArgsTypes...) const noexcept(<i>noex</i>);
  private:
    template&lt;class... T&gt;
      static constexpr bool <i>is-invocable-using</i> = <i>see below</i>;   <i>// exposition only</i>
  };
  
  <i>// [func.wrap.ref.deduct], deduction guides</i>
  template&lt;class F&gt;
    function_ref(F*) -&gt; function_ref&lt;F&gt;;
}
</pre><br><br><blockquote>
<h3 id="Constructors-and-assignment-operator" data-id="Constructors-and-assignment-operator"><a class="anchor hidden-xs" href="#Constructors-and-assignment-operator" title="Constructors-and-assignment-operator"><span class="octicon octicon-link"></span></a><span>Constructors and assignment operator</span></h3>
<p><span>[func.wrap.ref.ctor]</span></p>
</blockquote><pre>template&lt;class... T&gt;
  static constexpr bool <i>is-invocable-using</i> = <i>see below</i>;
</pre><blockquote>
<p><span>If </span><em><span>noex</span></em><span> is true, </span><code><i><span>is-invocable-using</span></i><span>&lt;T...&gt;</span></code><span> is equal to:</span></p>
<p><span>&nbsp;&nbsp;</span><code>is_nothrow_invocable_r_v&lt;R, T..., ArgTypes...&gt;</code></p>
<p><span>Otherwise, </span><code><i><span>is-invocable-using</span></i><span>&lt;T...&gt;</span></code><span> is equal to:</span></p>
<p><span>&nbsp;&nbsp;</span><code>is_invocable_r_v&lt;R, T..., ArgTypes...&gt;</code></p>
</blockquote><br><pre><code>template&lt;class F&gt; function_ref(F* f);
</code></pre><blockquote>
<p><em><span>Constraints:</span></em></p>
<ul>
<li><code>is_function_v&lt;F&gt;</code><span> is </span><code>true</code><span>, and</span></li>
<li><code><i><span>is-invocable-using</span></i><span>&lt;F&gt;</span></code><span> is </span><code>true</code><span>.</span></li>
</ul>
<p><em><span>Effects:</span></em><span> Constructs a </span><code>function_ref</code><span> object with the following properties:</span></p>
<ul>
<li><span>Its bound argument stores the value </span><code>f</code><span>.</span></li>
<li><span>Its target object points to a thunk with call pattern </span><code>invoke_r&lt;R&gt;(val, call_args...)</code><span>.</span></li>
</ul>
</blockquote><br><pre><code>template&lt;class F&gt; function_ref(F&amp;&amp; f);
</code></pre><blockquote>
<p><span>Let </span><code>U</code><span> be </span><code>remove_reference_t&lt;F&gt;</code><span>. If </span><code>remove_cv_t&lt;U&gt;</code><span> is </span><code>reference_wrapper&lt;X&gt;</code><span> for some </span><code>X</code><span>, let </span><code>T</code><span> be </span><code>X</code><span>; otherwise, </span><code>T</code><span> is </span><code>U</code><span>.</span></p>
<p><em><span>Constraints:</span></em></p>
<ul>
<li><code>remove_cvref_t&lt;F&gt;</code><span> is not the same type as </span><code>function_ref</code><span>, and</span></li>
<li><code><i><span>is-invocable-using</span></i><span>&lt;</span><i><span>cv</span></i><span> T&amp;&gt;</span></code><span> is </span><code>true</code><span>.</span></li>
</ul>
<p><em><span>Effects:</span></em><span> Constructs a </span><code>function_ref</code><span> object with the following properties:</span></p>
<ul>
<li><span>Its bound argument stores the value </span><code>addressof(static_cast&lt;T&amp;&gt;(f))</code><span>.</span></li>
<li><span>Its target object points to a thunk with call pattern </span><code>invoke_r&lt;R&gt;(obj, call_args...)</code><span> where </span><code>obj</code><span> is an invented variable introduced in:</span><br><br>
<span>&nbsp;&nbsp;</span><code><em><span>cv</span></em><span> T&amp; obj = *val;</span></code><br><br></li>
</ul>
</blockquote><br><pre><code>function_ref(const function_ref&amp; f) noexcept = default;
</code></pre><blockquote>
<p><em><span>Effects</span></em><span>: Constructs a </span><code>function_ref</code><span> object with a copy of </span><code>f</code><span>’s state entities.</span></p>
<p><em><span>Remarks:</span></em><span> This constructor is trivial.</span></p>
</blockquote><br><pre><code>function_ref&amp; operator=(const function_ref&amp; f) noexcept = default;
</code></pre><blockquote>
<p><em><span>Effects</span></em><span>: Replaces the state entities of </span><code>*this</code><span> with the state entities of </span><code>f</code><span>.</span></p>
<p><em><span>Returns:</span></em><span> </span><code>*this</code><span>.</span></p>
<p><em><span>Remarks:</span></em><span> This assignment operator is trivial.</span></p>
</blockquote><br><br><blockquote>
<h3 id="Invocation" data-id="Invocation"><a class="anchor hidden-xs" href="#Invocation" title="Invocation"><span class="octicon octicon-link"></span></a><span>Invocation</span></h3>
<p><span>[func.wrap.ref.inv]</span></p>
</blockquote><pre>R operator()(ArgsTypes... args) const noexcept(<i>noex</i>);
</pre><blockquote>
<p><span>Let </span><code>g</code><span> be the target object and </span><code>p</code><span> be the bound argument entity of </span><code>*this</code><span>.</span></p>
<p><em><span>Preconditions</span></em><span>: </span><code>p</code><span> stores a non-null pointer value.</span></p>
<p><em><span>Effects:</span></em><span> Equivalent to </span><code>return g(p, std::forward&lt;ArgTypes&gt;(args)...);</code></p>
</blockquote><br><br><blockquote>
<h3 id="Deduction-guides" data-id="Deduction-guides"><a class="anchor hidden-xs" href="#Deduction-guides" title="Deduction-guides"><span class="octicon octicon-link"></span></a><span>Deduction guides</span></h3>
<p><span>[func.wrap.ref.deduct]</span></p>
</blockquote><pre><code>template&lt;class F&gt;
  function_ref(F*) -&gt; function_ref&lt;F&gt;;
</code></pre><blockquote>
<p><em><span>Constraints:</span></em><span> </span><code>is_function_v&lt;F&gt;</code><span> is </span><code>true</code><span>.</span></p>
</blockquote><h2 id="Feature-test-macro" data-id="Feature-test-macro"><a class="anchor hidden-xs" href="#Feature-test-macro" title="Feature-test-macro"><span class="octicon octicon-link"></span></a><span>Feature test macro</span></h2><blockquote>
<p><span>Insert the following to </span><a href="https://eel.is/c++draft/version.syn" target="_blank" rel="noopener"><span>[version.syn]</span></a><span>, header </span><code>&lt;version&gt;</code><span> synopsis, after </span><code>__cpp_lib_move_only_function</code><span>:</span></p>
</blockquote><pre>#define __cpp_lib_function_ref 20XXXXL <i>// also in &lt;functional&gt;</i>
</pre><h2 id="Implementation-Experience" data-id="Implementation-Experience"><a class="anchor hidden-xs" href="#Implementation-Experience" title="Implementation-Experience"><span class="octicon octicon-link"></span></a><span>Implementation Experience</span></h2><p><span>Here is a macro-free implementation that supports </span><code>const</code><span> and </span><code>noexcept</code><span> qualifiers: </span><a href="https://github.com/zhihaoy/function_ref_nontype" target="_blank" rel="noopener"><span>[Github]</span></a><span> </span><a href="https://godbolt.org/z/991avvPxx" target="_blank" rel="noopener"><span>[Godbolt]</span></a></p><p><span>Sy Brand’s </span><code>tl::function_ref</code><span> </span><a href="https://github.com/TartanLlama/function_ref" target="_blank" rel="noopener"><span>[Github]</span></a><span> is distributed in vcpkg ports. This implementation does not support qualified signatures.</span></p><p><span>Many facilities similar to </span><code>function_ref</code><span> exist and are widely used in large codebases. Here are some examples:</span></p><ul>
<li><a href="https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/ADT/STLExtras.h" target="_blank" rel="noopener"><code>llvm::function_ref</code></a><span> from LLVM</span><sup class="footnote-ref"><a href="#fn7" id="fnref7">[7]</a></sup></li>
<li><a href="https://github.com/facebook/folly/blob/main/folly/Function.h" target="_blank" rel="noopener"><code>folly::FunctionRef</code></a><span> from Meta</span></li>
<li><a href="https://github.com/bminor/binutils-gdb/blob/master/gdbsupport/function-view.h" target="_blank" rel="noopener"><code>gdb::function_view</code></a><span> from GNU</span></li>
</ul><h2 id="Acknowledgments" data-id="Acknowledgments"><a class="anchor hidden-xs" href="#Acknowledgments" title="Acknowledgments"><span class="octicon octicon-link"></span></a><span>Acknowledgments</span></h2><p><span>Thanks to </span><strong><span>Agustín Bergé</span></strong><span>, </span><strong><span>Dietmar Kühl</span></strong><span>, </span><strong><span>Eric Niebler</span></strong><span>, </span><strong><span>Tim van Deurzen</span></strong><span>, and </span><strong><span>Alisdair Meredith</span></strong><span> for providing very valuable feedback on earlier drafts of this proposal.</span></p><p><span>Thanks to </span><strong><span>Jens Maurer</span></strong><span> for encouraging participation.</span></p><h2 id="References" data-id="References"><a class="anchor hidden-xs" href="#References" title="References"><span class="octicon octicon-link"></span></a><span>References</span></h2><hr class="footnotes-sep"><section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><em><span>function_ref: a non-owning reference to a Callable</span></em>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0792r5.html" target="_blank" rel="noopener"><span>http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0792r5.html</span></a> <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p><em><span>std::string_view accepting temporaries: good idea or horrible pitfall?</span></em>
<a href="https://www.foonathan.net/2017/03/string_view-temporary/" target="_blank" rel="noopener"><span>https://www.foonathan.net/2017/03/string_view-temporary/</span></a> <a href="#fnref2" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn3" class="footnote-item"><p><em><span>Implementing function_view is harder than you might think</span></em>
<a href="http://foonathan.net/blog/2017/01/20/function-ref-implementation.html" target="_blank" rel="noopener"><span>http://foonathan.net/blog/2017/01/20/function-ref-implementation.html</span></a> <a href="#fnref3" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn4" class="footnote-item"><p><em><span>On function_ref and string_view</span></em>
<a href="https://quuxplusone.github.io/blog/2019/05/10/function-ref-vs-string-view/" target="_blank" rel="noopener"><span>https://quuxplusone.github.io/blog/2019/05/10/function-ref-vs-string-view/</span></a> <a href="#fnref4" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn5" class="footnote-item"><p><em><span>Beyond operator(): NTTP callables in type-erased call wrappers</span></em>
<a href="http://wg21.link/p2511r0" target="_blank" rel="noopener"><span>http://wg21.link/p2511r0</span></a> <a href="#fnref5" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn6" class="footnote-item"><p><span>Extracting the Function Pointer from a Bound Pointer to Member Function.</span>
<em><span>Using the GNU Compiler Collection (GCC)</span></em>
<a href="https://gcc.gnu.org/onlinedocs/gcc/Bound-member-functions.html" target="_blank" rel="noopener"><span>https://gcc.gnu.org/onlinedocs/gcc/Bound-member-functions.html</span></a> <a href="#fnref6" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn7" class="footnote-item"><p><span>The function_ref class template.</span>
<em><span>LLVM Programmer’s Manual</span></em>
<a href="https://llvm.org/docs/ProgrammersManual.html#the-function-ref-class-template" target="_blank" rel="noopener"><span>https://llvm.org/docs/ProgrammersManual.html#the-function-ref-class-template</span></a> <a href="#fnref7" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section></div>
    <div class="ui-toc dropup unselectable hidden-print" style="display:none;">
        <div class="pull-right dropdown">
            <a id="tocLabel" class="ui-toc-label btn btn-default" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false" title="Table of content">
                <i class="fa fa-bars"></i>
            </a>
            <ul id="ui-toc" class="ui-toc-dropdown dropdown-menu" aria-labelledby="tocLabel">
                <div class="toc"><ul class="nav">
<li class=""><a href="#function_ref-a-type-erased-callable-reference" title="function_ref: a type-erased callable reference">function_ref: a type-erased callable reference</a><ul class="nav">
<li class=""><a href="#Table-of-contents" title="Table of contents">Table of contents</a></li>
<li class=""><a href="#Changelog" title="Changelog">Changelog</a><ul class="nav">
<li class=""><a href="#R6" title="R6">R6</a></li>
<li class=""><a href="#R5" title="R5">R5</a></li>
<li class=""><a href="#R4" title="R4">R4</a></li>
<li class=""><a href="#R3" title="R3">R3</a></li>
<li class=""><a href="#R2" title="R2">R2</a></li>
<li class=""><a href="#R1" title="R1">R1</a></li>
</ul>
</li>
<li class=""><a href="#Abstract" title="Abstract">Abstract</a></li>
<li class=""><a href="#Design-considerations" title="Design considerations">Design considerations</a><ul class="nav">
<li class=""><a href="#Question-1" title="Question 1">Question 1</a></li>
<li class=""><a href="#Question-2" title="Question 2">Question 2</a></li>
<li class=""><a href="#Question-3" title="Question 3">Question 3</a></li>
</ul>
</li>
<li class=""><a href="#Discussion" title="Discussion">Discussion</a><ul class="nav">
<li class=""><a href="#Is-stdfunction_ref-“parameter-only”" title="Is std::function_ref “parameter-only?”">Is std::function_ref “parameter-only?”</a></li>
<li><a href="#Is-this-only-a-lifetime-issue" title="Is this only a lifetime issue?">Is this only a lifetime issue?</a></li>
<li><a href="#Is-this-an-issue-or-non-issue" title="Is this an issue or non-issue?">Is this an issue or non-issue?</a></li>
</ul>
</li>
<li><a href="#Rationale" title="Rationale">Rationale</a><ul class="nav">
<li><a href="#Background-knowledge" title="Background knowledge">Background knowledge</a></li>
<li><a href="#Theory" title="Theory">Theory</a></li>
<li><a href="#Test" title="Test">Test</a></li>
<li><a href="#On-pointer-to-member" title="On pointer-to-member">On pointer-to-member</a></li>
</ul>
</li>
<li><a href="#Wording" title="Wording">Wording</a></li>
<li><a href="#Feature-test-macro" title="Feature test macro">Feature test macro</a></li>
<li><a href="#Implementation-Experience" title="Implementation Experience">Implementation Experience</a></li>
<li><a href="#Acknowledgments" title="Acknowledgments">Acknowledgments</a></li>
<li class=""><a href="#References" title="References">References</a></li>
</ul>
</li>
</ul>
</div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
            </ul>
        </div>
    </div>
    <div id="ui-toc-affix" class="ui-affix-toc ui-toc-dropdown unselectable hidden-print" data-spy="affix" style="top:17px;display:none;" null null>
        <div class="toc"><ul class="nav">
<li class=""><a href="#function_ref-a-type-erased-callable-reference" title="function_ref: a type-erased callable reference">function_ref: a type-erased callable reference</a><ul class="nav">
<li class=""><a href="#Table-of-contents" title="Table of contents">Table of contents</a></li>
<li class=""><a href="#Changelog" title="Changelog">Changelog</a><ul class="nav">
<li class=""><a href="#R6" title="R6">R6</a></li>
<li class=""><a href="#R5" title="R5">R5</a></li>
<li class=""><a href="#R4" title="R4">R4</a></li>
<li class=""><a href="#R3" title="R3">R3</a></li>
<li class=""><a href="#R2" title="R2">R2</a></li>
<li class=""><a href="#R1" title="R1">R1</a></li>
</ul>
</li>
<li class=""><a href="#Abstract" title="Abstract">Abstract</a></li>
<li class=""><a href="#Design-considerations" title="Design considerations">Design considerations</a><ul class="nav">
<li class=""><a href="#Question-1" title="Question 1">Question 1</a></li>
<li class=""><a href="#Question-2" title="Question 2">Question 2</a></li>
<li class=""><a href="#Question-3" title="Question 3">Question 3</a></li>
</ul>
</li>
<li class=""><a href="#Discussion" title="Discussion">Discussion</a><ul class="nav">
<li class=""><a href="#Is-stdfunction_ref-“parameter-only”" title="Is std::function_ref “parameter-only?”">Is std::function_ref “parameter-only?”</a></li>
<li><a href="#Is-this-only-a-lifetime-issue" title="Is this only a lifetime issue?">Is this only a lifetime issue?</a></li>
<li><a href="#Is-this-an-issue-or-non-issue" title="Is this an issue or non-issue?">Is this an issue or non-issue?</a></li>
</ul>
</li>
<li><a href="#Rationale" title="Rationale">Rationale</a><ul class="nav">
<li><a href="#Background-knowledge" title="Background knowledge">Background knowledge</a></li>
<li><a href="#Theory" title="Theory">Theory</a></li>
<li><a href="#Test" title="Test">Test</a></li>
<li><a href="#On-pointer-to-member" title="On pointer-to-member">On pointer-to-member</a></li>
</ul>
</li>
<li><a href="#Wording" title="Wording">Wording</a></li>
<li><a href="#Feature-test-macro" title="Feature test macro">Feature test macro</a></li>
<li><a href="#Implementation-Experience" title="Implementation Experience">Implementation Experience</a></li>
<li><a href="#Acknowledgments" title="Acknowledgments">Acknowledgments</a></li>
<li class=""><a href="#References" title="References">References</a></li>
</ul>
</li>
</ul>
</div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous" defer></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
    <script>
        var markdown = $(".markdown-body");
        //smooth all hash trigger scrolling
        function smoothHashScroll() {
            var hashElements = $("a[href^='#']").toArray();
            for (var i = 0; i < hashElements.length; i++) {
                var element = hashElements[i];
                var $element = $(element);
                var hash = element.hash;
                if (hash) {
                    $element.on('click', function (e) {
                        // store hash
                        var hash = this.hash;
                        if ($(hash).length <= 0) return;
                        // prevent default anchor click behavior
                        e.preventDefault();
                        // animate
                        $('body, html').stop(true, true).animate({
                            scrollTop: $(hash).offset().top
                        }, 100, "linear", function () {
                            // when done, add hash to url
                            // (default click behaviour)
                            window.location.hash = hash;
                        });
                    });
                }
            }
        }

        smoothHashScroll();
        var toc = $('.ui-toc');
        var tocAffix = $('.ui-affix-toc');
        var tocDropdown = $('.ui-toc-dropdown');
        //toc
        tocDropdown.click(function (e) {
            e.stopPropagation();
        });

        var enoughForAffixToc = true;

        function generateScrollspy() {
            $(document.body).scrollspy({
                target: ''
            });
            $(document.body).scrollspy('refresh');
            if (enoughForAffixToc) {
                toc.hide();
                tocAffix.show();
            } else {
                tocAffix.hide();
                toc.show();
            }
            $(document.body).scroll();
        }

        function windowResize() {
            //toc right
            var paddingRight = parseFloat(markdown.css('padding-right'));
            var right = ($(window).width() - (markdown.offset().left + markdown.outerWidth() - paddingRight));
            toc.css('right', right + 'px');
            //affix toc left
            var newbool;
            var rightMargin = (markdown.parent().outerWidth() - markdown.outerWidth()) / 2;
            //for ipad or wider device
            if (rightMargin >= 133) {
                newbool = true;
                var affixLeftMargin = (tocAffix.outerWidth() - tocAffix.width()) / 2;
                var left = markdown.offset().left + markdown.outerWidth() - affixLeftMargin;
                tocAffix.css('left', left + 'px');
            } else {
                newbool = false;
            }
            if (newbool != enoughForAffixToc) {
                enoughForAffixToc = newbool;
                generateScrollspy();
            }
        }
        $(window).resize(function () {
            windowResize();
        });
        $(document).ready(function () {
            windowResize();
            generateScrollspy();
        });

        //remove hash
        function removeHash() {
            window.location.hash = '';
        }

        var backtotop = $('.back-to-top');
        var gotobottom = $('.go-to-bottom');

        backtotop.click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            if (scrollToTop)
                scrollToTop();
            removeHash();
        });
        gotobottom.click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            if (scrollToBottom)
                scrollToBottom();
            removeHash();
        });

        var toggle = $('.expand-toggle');
        var tocExpand = false;

        checkExpandToggle();
        toggle.click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            tocExpand = !tocExpand;
            checkExpandToggle();
        })

        function checkExpandToggle () {
            var toc = $('.ui-toc-dropdown .toc');
            var toggle = $('.expand-toggle');
            if (!tocExpand) {
                toc.removeClass('expand');
                toggle.text('Expand all');
            } else {
                toc.addClass('expand');
                toggle.text('Collapse all');
            }
        }

        function scrollToTop() {
            $('body, html').stop(true, true).animate({
                scrollTop: 0
            }, 100, "linear");
        }

        function scrollToBottom() {
            $('body, html').stop(true, true).animate({
                scrollTop: $(document.body)[0].scrollHeight
            }, 100, "linear");
        }
    </script>
</body>

</html>
