<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>constexpr INVOKE</title>
<style type="text/css">html {
	position: relative;
	max-width: 1024px;
	height: 100%;
}
body {
	font-family: Helvetica, arial, sans-serif;
	font-size: 14px;
	line-height: 1.6;
	padding-top: 10px;
	padding-bottom: 10px;
	background-color: white;
	padding: 30px;
}
body>*:first-child {
	margin-top: 0 !important;
}
body>*:last-child {
	margin-bottom: 0 !important;
}
a {
	color: #4183C4;
}
a.absent {
	color: #cc0000;
}
a.anchor {
	display: block;
	padding-left: 30px;
	margin-left: -30px;
	cursor: pointer;
	position: absolute;
	top: 0;
	left: 0;
	bottom: 0;
}
h1, h2, h3, h4, h5, h6 {
	margin: 20px 0 10px;
	padding: 0;
	font-weight: bold;
	-webkit-font-smoothing: antialiased;
	cursor: text;
	position: relative;
}
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
	background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA09pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoMTMuMCAyMDEyMDMwNS5tLjQxNSAyMDEyLzAzLzA1OjIxOjAwOjAwKSAgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUM2NjlDQjI4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUM2NjlDQjM4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QzY2OUNCMDg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QzY2OUNCMTg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsQhXeAAAABfSURBVHjaYvz//z8DJYCRUgMYQAbAMBQIAvEqkBQWXI6sHqwHiwG70TTBxGaiWwjCTGgOUgJiF1J8wMRAIUA34B4Q76HUBelAfJYSA0CuMIEaRP8wGIkGMA54bgQIMACAmkXJi0hKJQAAAABJRU5ErkJggg==) no-repeat 10px center;
	text-decoration: none;
}
h1 tt, h1 code {
	font-size: inherit;
}
h2 tt, h2 code {
	font-size: inherit;
}
h3 tt, h3 code {
	font-size: inherit;
}
h4 tt, h4 code {
	font-size: inherit;
}
h5 tt, h5 code {
	font-size: inherit;
}
h6 tt, h6 code {
	font-size: inherit;
}
h1 {
	font-size: 28px;
	color: black;
}
h2 {
	font-size: 24px;
	border-bottom: 1px solid #cccccc;
	color: black;
}
h3 {
	font-size: 18px;
}
h4 {
	font-size: 16px;
}
h5 {
	font-size: 14px;
}
h6 {
	color: #777777;
	font-size: 14px;
}
p, blockquote, ol, dl, li, table, pre {
	margin: 15px 0;
}
hr {
	background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC) repeat-x 0 0;
	border: 0 none;
	color: #cccccc;
	height: 4px;
	padding: 0;
}
body>h2:first-child {
	margin-top: 0;
	padding-top: 0;
}
body>h1:first-child {
	margin-top: 0;
	padding-top: 0;
}
body>h1:first-child+h2 {
	margin-top: 0;
	padding-top: 0;
}
body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
	margin-top: 0;
	padding-top: 0;
}
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
	margin-top: 0;
	padding-top: 0;
}
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
	margin-top: 0;
}
li p.first {
	display: inline-block;
}
li {
	margin: 0;
}
ol {
	padding-left: 30px;
    margin: 5px;
    counter-reset: item;
    margin-left: -1px;
    margin-bottom: -1px;
    margin-top: -1px;
}
ol > li {
    counter-increment: item;
    margin-bottom: -1px;
    margin-top: -1px;    
}
ol ol > li {
    display: block;
    margin-bottom: -1px;
    margin-top: -1px;    
}
ol ol > li:before {
    content: counters(item, ".") ". ";
    margin-left: -30px;
    margin-bottom: -1px;
    margin-top: -1px;    
}
ul :first-child, ol :first-child {
	margin-top: 0;
}
ul ul { 
    margin-left: -15px;
}
dl {
	padding: 0;
}
dl dt {
	font-size: 14px;
	font-weight: bold;
	font-style: italic;
	padding: 0;
	margin: 15px 0 5px;
}
dl dt:first-child {
	padding: 0;
}
dl dt> :first-child {
	margin-top: 0;
}
dl dt> :last-child {
	margin-bottom: 0;
}
dl dd {
	margin: 0 0 15px;
	padding: 0 15px;
}
dl dd> :first-child {
	margin-top: 0;
}
dl dd> :last-child {
	margin-bottom: 0;
}
blockquote {
	border-left: 4px solid #dddddd;
	padding: 0 15px;
	color: #777777;
}
blockquote> :first-child {
	margin-top: 0;
}
blockquote> :last-child {
	margin-bottom: 0;
}
table {
	padding: 0;
	border-collapse: collapse;
}
table tr {
	border-top: 1px solid #cccccc;
	background-color: white;
	margin: 0;
	padding: 0;
}
table tr:nth-child(2n) {
	background-color: #f8f8f8;
}
table tr th {
	font-weight: bold;
	border: 1px solid #cccccc;
	margin: 0;
	padding: 6px 13px;
}
table tr td {
	border: 1px solid #cccccc;
	margin: 0;
	padding: 6px 13px;
}
table tr th :first-child, table tr td :first-child {
	margin-top: 0;
}
table tr th :last-child, table tr td :last-child {
	margin-bottom: 0;
}
td {
	vertical-align: top;
}
img {
	max-width: 100%;
}
span.frame {
	display: block;
	overflow: hidden;
}
span.frame>span {
	border: 1px solid #dddddd;
	display: block;
	float: left;
	overflow: hidden;
	margin: 13px 0 0;
	padding: 7px;
	width: auto;
}
span.frame span img {
	display: block;
	float: left;
}
span.frame span span {
	clear: both;
	color: #333333;
	display: block;
	padding: 5px 0 0;
}
span.align-center {
	display: block;
	overflow: hidden;
	clear: both;
}
span.align-center>span {
	display: block;
	overflow: hidden;
	margin: 13px auto 0;
	text-align: center;
}
span.align-center span img {
	margin: 0 auto;
	text-align: center;
}
span.align-right {
	display: block;
	overflow: hidden;
	clear: both;
}
span.align-right>span {
	display: block;
	overflow: hidden;
	margin: 13px 0 0;
	text-align: right;
}
span.align-right span img {
	margin: 0;
	text-align: right;
}
span.float-left {
	display: block;
	margin-right: 13px;
	overflow: hidden;
	float: left;
}
span.float-left span {
	margin: 13px 0 0;
}
span.float-right {
	display: block;
	margin-left: 13px;
	overflow: hidden;
	float: right;
}
span.float-right>span {
	display: block;
	overflow: hidden;
	margin: 13px auto 0;
	text-align: right;
}
code, tt {
	margin: 0 2px;
	padding: 0 5px;
	white-space: nowrap;
	border: 1px solid #eaeaea;
	background-color: #f8f8f8;
	border-radius: 3px;
}
pre code {
	margin: 0;
	padding: 0;
	white-space: pre;
	border: none;
	background: transparent;
}
.highlight pre {
	background-color: #f8f8f8;
	border: 1px solid #cccccc;
	font-size: 13px;
	line-height: 19px;
	overflow: auto;
	padding: 6px 10px;
	border-radius: 3px;
}
pre {
	background-color: #f8f8f8;
	border: 1px solid #cccccc;
	font-size: 13px;
	line-height: 19px;
	overflow: auto;
    overflow-x: hidden;
    overflow-y: hidden;
    padding: 6px 10px;
	border-radius: 3px;
}
pre code, pre tt {
	background-color: transparent;
	border: none;
}
sup {
	font-size: 0.83em;
	vertical-align: super;
	line-height: 0;
}
kbd {
	display: inline-block;
	padding: 3px 5px;
	font-size: 11px;
	line-height: 10px;
	color: #555;
	vertical-align: middle;
	background-color: #fcfcfc;
	border: solid 1px #ccc;
	border-bottom-color: #bbb;
	border-radius: 3px;
	box-shadow: inset 0 -1px 0 #bbb
}
* {
	-webkit-print-color-adjust: exact;
}
ins {
	color: #00A000
}
del {
	color: #A00000
}
a.self-link {
    position: absolute;
    top: 0;
    left: calc(-1 * (3.5rem - 26px));
    width: calc(3.5rem - 26px);
    height: 2em;
    text-align: center;
    border: none;
    transition: opacity .2s;
    opacity: .5;
    font-size: 83%;
}
a.self-link:hover {
    opacity: 1;
}
a.self-link::before {
    content: "§";
}</style>
<style type="text/css">/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+c+cpp&plugins=line-highlight */
/**
 * prism.js default theme for JavaScript, CSS and HTML
 * Based on dabblet (http://dabblet.com)
 * @author Lea Verou
 */

code[class*="language-"],
pre[class*="language-"] {
	color: black;
	background: none;
	text-shadow: 0 1px white;
	font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
	text-align: left;
	white-space: pre;
	word-spacing: normal;
	word-break: normal;
	word-wrap: normal;
	line-height: 1.5;

	-moz-tab-size: 4;
	-o-tab-size: 4;
	tab-size: 4;

	-webkit-hyphens: none;
	-moz-hyphens: none;
	-ms-hyphens: none;
	hyphens: none;
}

pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
	text-shadow: none;
	background: #b3d4fc;
}

pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
	text-shadow: none;
	background: #b3d4fc;
}

@media print {
	code[class*="language-"],
	pre[class*="language-"] {
		text-shadow: none;
	}
}

/* Code blocks */
pre[class*="language-"] {
	padding: 1em;
	margin: .5em 0;
	overflow: auto;
}

:not(pre) > code[class*="language-"],
pre[class*="language-"] {
	background: #f8f8f8;
}

/* Inline code */
:not(pre) > code[class*="language-"] {
	padding: .1em;
	border-radius: .3em;
	white-space: normal;
}

.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
	color: slategray;
}

.token.punctuation {
	color: #999;
}

.namespace {
	opacity: .7;
}

.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
	color: #905;
}

.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
	color: #690;
}

.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
	color: #9a6e3a;
}

.token.atrule,
.token.attr-value,
.token.keyword {
	color: #07a;
}

.token.function,
.token.class-name {
	color: #DD4A68;
}

.token.regex,
.token.important,
.token.variable {
	color: #e90;
}

.token.important,
.token.bold {
	font-weight: bold;
}
.token.italic {
	font-style: italic;
}

.token.entity {
	cursor: help;
}

pre[data-line] {
	position: relative;
	padding: 1em 0 1em 3em;
}

.line-highlight {
	position: absolute;
	left: 0;
	right: 0;
	padding: inherit 0;
	margin-top: 1em; /* Same as .prism’s padding-top */

	background: hsla(24, 20%, 50%,.08);
	background: linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));

	pointer-events: none;

	line-height: inherit;
	white-space: pre;
}

	.line-highlight:before,
	.line-highlight[data-end]:after {
		content: attr(data-start);
		position: absolute;
		top: .4em;
		left: .6em;
		min-width: 1em;
		padding: 0 .5em;
		background-color: hsla(24, 20%, 50%,.4);
		color: hsl(24, 20%, 95%);
		font: bold 65%/1.5 sans-serif;
		text-align: center;
		vertical-align: .3em;
		border-radius: 999px;
		text-shadow: none;
		box-shadow: 0 1px white;
	}

	.line-highlight[data-end]:after {
		content: attr(data-end);
		top: auto;
		bottom: .4em;
	}

.line-numbers .line-highlight:before,
.line-numbers .line-highlight:after {
	content: none;
}

</style>
<script type="text/javascript">/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+c+cpp+nasm+rust&plugins=line-highlight */
var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-([\w-]+)\b/i,t=0,n=_self.Prism={manual:_self.Prism&&_self.Prism.manual,disableWorkerMessageHandler:_self.Prism&&_self.Prism.disableWorkerMessageHandler,util:{encode:function(e){return e instanceof r?new r(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function(e,t){var r=n.util.type(e);switch(t=t||{},r){case"Object":if(t[n.util.objId(e)])return t[n.util.objId(e)];var a={};t[n.util.objId(e)]=a;for(var l in e)e.hasOwnProperty(l)&&(a[l]=n.util.clone(e[l],t));return a;case"Array":if(t[n.util.objId(e)])return t[n.util.objId(e)];var a=[];return t[n.util.objId(e)]=a,e.forEach(function(e,r){a[r]=n.util.clone(e,t)}),a}return e}},languages:{extend:function(e,t){var r=n.util.clone(n.languages[e]);for(var a in t)r[a]=t[a];return r},insertBefore:function(e,t,r,a){a=a||n.languages;var l=a[e];if(2==arguments.length){r=arguments[1];for(var i in r)r.hasOwnProperty(i)&&(l[i]=r[i]);return l}var o={};for(var s in l)if(l.hasOwnProperty(s)){if(s==t)for(var i in r)r.hasOwnProperty(i)&&(o[i]=r[i]);o[s]=l[s]}var u=a[e];return a[e]=o,n.languages.DFS(n.languages,function(t,n){n===u&&t!=e&&(this[t]=o)}),o},DFS:function(e,t,r,a){a=a||{};for(var l in e)e.hasOwnProperty(l)&&(t.call(e,l,e[l],r||l),"Object"!==n.util.type(e[l])||a[n.util.objId(e[l])]?"Array"!==n.util.type(e[l])||a[n.util.objId(e[l])]||(a[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,l,a)):(a[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,null,a)))}},plugins:{},highlightAll:function(e,t){n.highlightAllUnder(document,e,t)},highlightAllUnder:function(e,t,r){var a={callback:r,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};n.hooks.run("before-highlightall",a);for(var l,i=a.elements||e.querySelectorAll(a.selector),o=0;l=i[o++];)n.highlightElement(l,t===!0,a.callback)},highlightElement:function(t,r,a){for(var l,i,o=t;o&&!e.test(o.className);)o=o.parentNode;o&&(l=(o.className.match(e)||[,""])[1].toLowerCase(),i=n.languages[l]),t.className=t.className.replace(e,"").replace(/\s+/g," ")+" language-"+l,t.parentNode&&(o=t.parentNode,/pre/i.test(o.nodeName)&&(o.className=o.className.replace(e,"").replace(/\s+/g," ")+" language-"+l));var s=t.textContent,u={element:t,language:l,grammar:i,code:s};if(n.hooks.run("before-sanity-check",u),!u.code||!u.grammar)return u.code&&(n.hooks.run("before-highlight",u),u.element.textContent=u.code,n.hooks.run("after-highlight",u)),n.hooks.run("complete",u),void 0;if(n.hooks.run("before-highlight",u),r&&_self.Worker){var g=new Worker(n.filename);g.onmessage=function(e){u.highlightedCode=e.data,n.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,a&&a.call(u.element),n.hooks.run("after-highlight",u),n.hooks.run("complete",u)},g.postMessage(JSON.stringify({language:u.language,code:u.code,immediateClose:!0}))}else u.highlightedCode=n.highlight(u.code,u.grammar,u.language),n.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,a&&a.call(t),n.hooks.run("after-highlight",u),n.hooks.run("complete",u)},highlight:function(e,t,a){var l={code:e,grammar:t,language:a};return n.hooks.run("before-tokenize",l),l.tokens=n.tokenize(l.code,l.grammar),n.hooks.run("after-tokenize",l),r.stringify(n.util.encode(l.tokens),l.language)},matchGrammar:function(e,t,r,a,l,i,o){var s=n.Token;for(var u in r)if(r.hasOwnProperty(u)&&r[u]){if(u==o)return;var g=r[u];g="Array"===n.util.type(g)?g:[g];for(var c=0;c<g.length;++c){var h=g[c],f=h.inside,d=!!h.lookbehind,m=!!h.greedy,p=0,y=h.alias;if(m&&!h.pattern.global){var v=h.pattern.toString().match(/[imuy]*$/)[0];h.pattern=RegExp(h.pattern.source,v+"g")}h=h.pattern||h;for(var b=a,k=l;b<t.length;k+=t[b].length,++b){var w=t[b];if(t.length>e.length)return;if(!(w instanceof s)){if(m&&b!=t.length-1){h.lastIndex=k;var _=h.exec(e);if(!_)break;for(var j=_.index+(d?_[1].length:0),P=_.index+_[0].length,A=b,x=k,O=t.length;O>A&&(P>x||!t[A].type&&!t[A-1].greedy);++A)x+=t[A].length,j>=x&&(++b,k=x);if(t[b]instanceof s)continue;I=A-b,w=e.slice(k,x),_.index-=k}else{h.lastIndex=0;var _=h.exec(w),I=1}if(_){d&&(p=_[1]?_[1].length:0);var j=_.index+p,_=_[0].slice(p),P=j+_.length,N=w.slice(0,j),S=w.slice(P),C=[b,I];N&&(++b,k+=N.length,C.push(N));var E=new s(u,f?n.tokenize(_,f):_,y,_,m);if(C.push(E),S&&C.push(S),Array.prototype.splice.apply(t,C),1!=I&&n.matchGrammar(e,t,r,b,k,!0,u),i)break}else if(i)break}}}}},tokenize:function(e,t){var r=[e],a=t.rest;if(a){for(var l in a)t[l]=a[l];delete t.rest}return n.matchGrammar(e,r,t,0,0,!1),r},hooks:{all:{},add:function(e,t){var r=n.hooks.all;r[e]=r[e]||[],r[e].push(t)},run:function(e,t){var r=n.hooks.all[e];if(r&&r.length)for(var a,l=0;a=r[l++];)a(t)}}},r=n.Token=function(e,t,n,r,a){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length,this.greedy=!!a};if(r.stringify=function(e,t,a){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return r.stringify(n,t,e)}).join("");var l={type:e.type,content:r.stringify(e.content,t,a),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:a};if(e.alias){var i="Array"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}n.hooks.run("wrap",l);var o=Object.keys(l.attributes).map(function(e){return e+'="'+(l.attributes[e]||"").replace(/"/g,"&quot;")+'"'}).join(" ");return"<"+l.tag+' class="'+l.classes.join(" ")+'"'+(o?" "+o:"")+">"+l.content+"</"+l.tag+">"},!_self.document)return _self.addEventListener?(n.disableWorkerMessageHandler||_self.addEventListener("message",function(e){var t=JSON.parse(e.data),r=t.language,a=t.code,l=t.immediateClose;_self.postMessage(n.highlight(a,n.languages[r],r)),l&&_self.close()},!1),_self.Prism):_self.Prism;var a=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return a&&(n.filename=a.src,n.manual||a.hasAttribute("data-manual")||("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(n.highlightAll):window.setTimeout(n.highlightAll,16):document.addEventListener("DOMContentLoaded",n.highlightAll))),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
Prism.languages.markup={comment:/<!--[\s\S]*?-->/,prolog:/<\?[\s\S]+?\?>/,doctype:/<!DOCTYPE[\s\S]+?>/i,cdata:/<!\[CDATA\[[\s\S]*?]]>/i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+)/i,inside:{punctuation:[/^=/,{pattern:/(^|[^\\])["']/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&amp;/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup;
Prism.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(?:;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^{}\s][^{};]*?(?=\s*\{)/,string:{pattern:/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},property:/[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.languages.css,Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/(<style[\s\S]*?>)[\s\S]*?(?=<\/style>)/i,lookbehind:!0,inside:Prism.languages.css,alias:"language-css",greedy:!0}}),Prism.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:Prism.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:Prism.languages.css}},alias:"language-css"}},Prism.languages.markup.tag));
Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(?:true|false)\b/,"function":/\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/};
Prism.languages.c=Prism.languages.extend("clike",{keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*\/%&|^!=<>]=?/,number:/(?:\b0x[\da-f]+|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?)[ful]*/i}),Prism.languages.insertBefore("c","string",{macro:{pattern:/(^\s*)#\s*[a-z]+(?:[^\r\n\\]|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,alias:"property",inside:{string:{pattern:/(#\s*include\s*)(?:<.+?>|("|')(?:\\?.)+?\2)/,lookbehind:!0},directive:{pattern:/(#\s*)\b(?:define|defined|elif|else|endif|error|ifdef|ifndef|if|import|include|line|pragma|undef|using)\b/,lookbehind:!0,alias:"keyword"}}},constant:/\b(?:__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|stdin|stdout|stderr)\b/}),delete Prism.languages.c["class-name"],delete Prism.languages.c["boolean"];
Prism.languages.cpp=Prism.languages.extend("c",{keyword:/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,"boolean":/\b(?:true|false)\b/,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*\/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/}),Prism.languages.insertBefore("cpp","keyword",{"class-name":{pattern:/(class\s+)\w+/i,lookbehind:!0}}),Prism.languages.insertBefore("cpp","string",{"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}});
Prism.languages.nasm={comment:/;.*$/m,string:/(["'`])(?:\\.|(?!\1)[^\\\r\n])*\1/,label:{pattern:/(^\s*)[A-Za-z._?$][\w.?$@~#]*:/m,lookbehind:!0,alias:"function"},keyword:[/\[?BITS (?:16|32|64)\]?/,{pattern:/(^\s*)section\s*[a-zA-Z.]+:?/im,lookbehind:!0},/(?:extern|global)[^;\r\n]*/i,/(?:CPU|FLOAT|DEFAULT).*$/m],register:{pattern:/\b(?:st\d|[xyz]mm\d\d?|[cdt]r\d|r\d\d?[bwd]?|[er]?[abcd]x|[abcd][hl]|[er]?(?:bp|sp|si|di)|[cdefgs]s)\b/i,alias:"variable"},number:/(?:\b|(?=\$))(?:0[hx][\da-f]*\.?[\da-f]+(?:p[+-]?\d+)?|\d[\da-f]+[hx]|\$\d[\da-f]*|0[oq][0-7]+|[0-7]+[oq]|0[by][01]+|[01]+[by]|0[dt]\d+|\d*\.?\d+(?:\.?e[+-]?\d+)?[dt]?)\b/i,operator:/[\[\]*+\-\/%<>=&|$!]/};
Prism.languages.rust={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:[{pattern:/b?r(#*)"(?:\\.|(?!"\1)[^\\\r\n])*"\1/,greedy:!0},{pattern:/b?"(?:\\.|[^\\\r\n"])*"/,greedy:!0}],"char":{pattern:/b?'(?:\\(?:x[0-7][\da-fA-F]|u{(?:[\da-fA-F]_*){1,6}|.)|[^\\\r\n\t'])'/,alias:"string"},"lifetime-annotation":{pattern:/'[^\s>']+/,alias:"symbol"},keyword:/\b(?:abstract|alignof|as|be|box|break|const|continue|crate|do|else|enum|extern|false|final|fn|for|if|impl|in|let|loop|match|mod|move|mut|offsetof|once|override|priv|pub|pure|ref|return|sizeof|static|self|struct|super|true|trait|type|typeof|unsafe|unsized|use|virtual|where|while|yield)\b/,attribute:{pattern:/#!?\[.+?\]/,greedy:!0,alias:"attr-name"},"function":[/\w+(?=\s*\()/,/\w+!(?=\s*\(|\[)/],"macro-rules":{pattern:/\w+!/,alias:"function"},number:/\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(\d(?:_?\d)*)?\.?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)(?:_?(?:[iu](?:8|16|32|64)?|f32|f64))?\b/,"closure-params":{pattern:/\|[^|]*\|(?=\s*[{-])/,inside:{punctuation:/[|:,]/,operator:/[&*]/}},punctuation:/[{}[\];(),:]|\.+|->/,operator:/[-+*\/%!^]=?|=[=>]?|@|&[&=]?|\|[|=]?|<<?=?|>>?=?/};
!function(){function e(e,t){return Array.prototype.slice.call((t||document).querySelectorAll(e))}function t(e,t){return t=" "+t+" ",(" "+e.className+" ").replace(/[\n\t]/g," ").indexOf(t)>-1}function n(e,n,i){n="string"==typeof n?n:e.getAttribute("data-line");for(var o,l=n.replace(/\s+/g,"").split(","),a=+e.getAttribute("data-line-offset")||0,s=r()?parseInt:parseFloat,d=s(getComputedStyle(e).lineHeight),u=t(e,"line-numbers"),c=0;o=l[c++];){var p=o.split("-"),m=+p[0],f=+p[1]||m,h=e.querySelector('.line-highlight[data-range="'+o+'"]')||document.createElement("div");if(h.setAttribute("aria-hidden","true"),h.setAttribute("data-range",o),h.className=(i||"")+" line-highlight",u&&Prism.plugins.lineNumbers){var g=Prism.plugins.lineNumbers.getLine(e,m),y=Prism.plugins.lineNumbers.getLine(e,f);g&&(h.style.top=g.offsetTop+"px"),y&&(h.style.height=y.offsetTop-g.offsetTop+y.offsetHeight+"px")}else h.setAttribute("data-start",m),f>m&&h.setAttribute("data-end",f),h.style.top=(m-a-1)*d+"px",h.textContent=new Array(f-m+2).join(" \n");u?e.appendChild(h):(e.querySelector("code")||e).appendChild(h)}}function i(){var t=location.hash.slice(1);e(".temporary.line-highlight").forEach(function(e){e.parentNode.removeChild(e)});var i=(t.match(/\.([\d,-]+)$/)||[,""])[1];if(i&&!document.getElementById(t)){var r=t.slice(0,t.lastIndexOf(".")),o=document.getElementById(r);o&&(o.hasAttribute("data-line")||o.setAttribute("data-line",""),n(o,i,"temporary "),document.querySelector(".temporary.line-highlight").scrollIntoView())}}if("undefined"!=typeof self&&self.Prism&&self.document&&document.querySelector){var r=function(){var e;return function(){if("undefined"==typeof e){var t=document.createElement("div");t.style.fontSize="13px",t.style.lineHeight="1.5",t.style.padding=0,t.style.border=0,t.innerHTML="&nbsp;<br />&nbsp;",document.body.appendChild(t),e=38===t.offsetHeight,document.body.removeChild(t)}return e}}(),o=0;Prism.hooks.add("before-sanity-check",function(t){var n=t.element.parentNode,i=n&&n.getAttribute("data-line");if(n&&i&&/pre/i.test(n.nodeName)){var r=0;e(".line-highlight",n).forEach(function(e){r+=e.textContent.length,e.parentNode.removeChild(e)}),r&&/^( \n)+$/.test(t.code.slice(-r))&&(t.code=t.code.slice(0,-r))}}),Prism.hooks.add("complete",function l(e){var r=e.element.parentNode,a=r&&r.getAttribute("data-line");if(r&&a&&/pre/i.test(r.nodeName)){clearTimeout(o);var s=Prism.plugins.lineNumbers,d=e.plugins&&e.plugins.lineNumbers;t(r,"line-numbers")&&s&&!d?Prism.hooks.add("line-numbers",l):(n(r,a),o=setTimeout(i,1))}}),window.addEventListener("hashchange",i),window.addEventListener("resize",function(){var e=document.querySelectorAll("pre[data-line]");Array.prototype.forEach.call(e,function(e){n(e)})})}}();
</script>

</head>
<body>
<address align=right>
Document Number: P1065R0 <br />
Date: 2018-10-07 <br />
Audience: LEWG, LWG <br />
Reply-To: Barry Revzin, barry dot revzin at gmail dot com <br />
</address>
<hr /><h1 align=center><p>constexpr <code><i>INVOKE</i></code></p></h1>
<h2>Contents</h2>
<div class="toc">
<ol>
<li><a href="#motivation">Motivation</a></li>
<li><a href="#history">History</a></li>
<li><a href="#proposal">Proposal</a><ol>
<li><a href="#wording">Wording</a></li>
</ol>
</li>
<li><a href="#acknowledgements">Acknowledgements</a></li>
<li><a href="#references">References</a></li>
</ol>
</div>

<h2 id="motivation">1. Motivation<a class="self-link" href="#motivation"></a></h2>
<p>Currently, one of the most important utility functions in the standard libary, <code class="language-cpp">std::invoke()</code>, is not <code class="language-cpp">constexpr</code>. Even though <code class="language-cpp">std::apply()</code> and <code class="language-cpp">std::visit()</code>, both of which rely on <code><i>INVOKE</i></code>, are both <code class="language-cpp">constexpr</code>. The standard library thus finds itself in an odd state where <code class="language-cpp">std::invoke()</code> is and is not <code class="language-cpp">constexpr</code>. </p>
<p>The reason that <code class="language-cpp">std::invoke()</code> is not <code class="language-cpp">constexpr</code> has some interesting history associated with it. But at this point, it is simply history, and there is no further blocker to making this change. This proposal resolves <a href="https://wg21.link/lwg2894" title="The function template std::apply() is required to be constexpr, but std::invoke() isn't">LWG 2894</a> but also goes one step further and addresses various other <code><i>INVOKE</i></code>-related machinery.</p>
<h2 id="history">2. History<a class="self-link" href="#history"></a></h2>
<p>Our tale beings in April, 2015 with <a href="https://bugs.llvm.org/show_bug.cgi?id=23141" title="std::bind const-qualifying bound arguments captured by value when compiled as C++14">llvm bug 23141</a>, which presented this code which broke in clang in C++14 (but had compiled in C++11 mode) due to the introduction of a <code class="language-cpp">constexpr __invoke</code> (which ended up breaking range-v3):</p>
<pre class="codehilite"><code class="language-cpp">#include &lt;functional&gt;
#include &lt;type_traits&gt;

struct Fun
{
  template&lt;typename T, typename U&gt;
  void operator()(T &amp;&amp; t, U &amp;&amp; u) const
  {
    static_assert(std::is_same&lt;U, int &amp;&gt;::value, &quot;&quot;);
  }
};

int main()
{
    std::bind(Fun{}, std::placeholders::_1, 42)(&quot;hello&quot;);
}</code></pre>


<p>as well as the similar <a href="https://bugs.llvm.org/show_bug.cgi?id=23135" title="[C++11/14] Body of constexpr function templates instantiated too eagerly in unevaluated operands">llvm bug 23135</a>, which was about this program:</p>
<pre class="codehilite"><code class="language-cpp">template&lt;typename T&gt;
int f(T x)
{
    return x.get();
}

template&lt;typename T&gt;
constexpr int g(T x)
{
    return x.get();
}

int main() {

  // O.K. The body of `f' is not required.
  decltype(f(0)) a;

  // Seems to instantiate the body of `g'
  // and results in an error.
  decltype(g(0)) b;

  return 0;
}</code></pre>


<p>In both cases the fundamental issue was eager instantiation of the body, which doesn't actually seem necessary to determine the results here. In neither example is the return type deduced.</p>
<p>These are incarnations of <a href="https://wg21.link/cwg1581" title="When are constexpr member functions defined?">CWG 1581</a>, which dealt with the question of when, exactly, are <code class="language-cpp">constexpr</code> functions defined. In the broken programs above, the <code class="language-cpp">constexpr</code> functions (the non-<code class="language-cpp">const</code> call operator of the binder object being returned in the first case and <code class="language-cpp">g()</code> in the second) were eagerly instantiated, triggering hard compile errors, in cases where the program ultimately would not have required their instantiation. </p>
<p>Thankfully, this difficult problem has been resolved by the adoption of <a href="https://wg21.link/p0859" title="Core Issue 1581: When are constexpr member functions defined?">P0859</a> in Albuquerque, 2017. As a result, both of the above programs are valid. </p>
<p>This issue was the blocker for having a <code class="language-cpp">constexpr std::invoke()</code> due to this eager instantiation issue - which no longer exists. </p>
<h2 id="proposal">3. Proposal<a class="self-link" href="#proposal"></a></h2>
<p>This proposal adds <code class="language-cpp">constexpr</code> to the following <code><i>INVOKE</i></code>-related machinery: <code class="language-cpp">invoke()</code>, <code class="language-cpp">reference_wrapper&lt;T&gt;</code>, <code class="language-cpp">not_fn()</code>, <code class="language-cpp">bind()</code>, and <code class="language-cpp">mem_fn()</code>. The remaining non-<code class="language-cpp">constexpr</code> elements of the library that are <code><i>INVOKE</i></code>-adjacent are <code class="language-cpp">function&lt;Sig&gt;</code>, <code class="language-cpp">packaged_task&lt;Sig&gt;</code>, <code class="language-cpp">async()</code>, <code class="language-cpp">thread</code>, and <code class="language-cpp">call_once()</code>.</p>
<p>The entirety of the wording is the addition of the <code class="language-cpp">constexpr</code> keyword in 22 places.</p>
<h3 id="wording">3.1. Wording<a class="self-link" href="#wording"></a></h3>
<p>Add <code class="language-cpp">constexpr</code> to several places in the synopsis in 19.14.1 [functional.syn]</p>
<blockquote><pre class="codehilite"><code class="language-cpp">namespace std {
  // [func.invoke], invoke
  template&lt;class F, class... Args>
    </code><code><ins>constexpr</ins></code> <code class="language-cpp">invoke_result_t&lt;F, Args...> invoke(F&& f, Args&&... args)
      noexcept(is_nothrow_invocable_v&lt;F, Args...>);

  // [refwrap], reference_­wrapper
  template&lt;class T> class reference_wrapper;

  template&lt;class T> </code><code><ins>constexpr</ins></code> <code class="language-cpp">reference_wrapper&lt;T> ref(T&) noexcept;
  template&lt;class T> </code><code><ins>constexpr</ins></code> <code class="language-cpp">reference_wrapper&lt;const T> cref(const T&) noexcept;
  template&lt;class T> void ref(const T&&) = delete;
  template&lt;class T> void cref(const T&&) = delete;

  template&lt;class T> </code><code><ins>constexpr</ins></code> <code class="language-cpp">reference_wrapper&lt;T> ref(reference_wrapper&lt;T>) noexcept;
  template&lt;class T> </code><code><ins>constexpr</ins></code> <code class="language-cpp">reference_wrapper&lt;const T> cref(reference_wrapper&lt;T>) noexcept;

  // [arithmetic.operations], arithmetic operations
  // ...

  // [comparisons], comparisons
  // ...

  // [logical.operations], logical operations
  // ...

  // [bitwise.operations], bitwise operations
  // ...

  // [func.identity], identity
  // ...

  // [func.not_fn], function template not_­fn
  template&lt;class F> </code><code><ins>constexpr</ins></code> <i>unspecified</i><code class="language-cpp"> not_fn(F&& f);

  // [func.bind], bind
  template&lt;class T> struct is_bind_expression;
  template&lt;class T> struct is_placeholder;

  template&lt;class F, class... BoundArgs>
    </code><code><ins>constexpr</ins></code> <i>unspecified</i><code class="language-cpp"> bind(F&&, BoundArgs&&...);
  template&lt;class R, class F, class... BoundArgs>
    </code><code><ins>constexpr</ins></code> <i>unspecified</i><code class="language-cpp"> bind(F&&, BoundArgs&&...);

  namespace placeholders {
    // M is the implementation-defined number of placeholders
    see below _1;
    see below _2;
               .
               .
               .
    see below _M;
  }

  // [func.memfn], member function adaptors
  template&lt;class R, class T>
    </code><code><ins>constexpr</ins></code> <i>unspecified</i><code class="language-cpp"> mem_fn(R T::*) noexcept;

  // ...    
}</code></pre></blockquote>

<p>Add <code class="language-cpp">constexpr</code> to the requirements of <i>forwarding call wrapper</i> in 19.4.3 [func.require]</p>
<blockquote>
<p>Every call wrapper ([func.def]) shall be <i>Cpp17MoveConstructible</i>. A <i>forwarding call wrapper</i> is a call wrapper that can be called with an arbitrary argument list and delivers the arguments to the wrapped callable object as references. This forwarding step shall ensure that rvalue arguments are delivered as rvalue references and lvalue arguments are delivered as lvalue references. <ins>The defaulted move and copy constructor, respectively, of a forwarding call wrapper shall be a constexpr function if and only if
all required element-wise initializations for copy and move, respectively, would satisfy the requirements for a constexpr function. The call operator of a forwarding call wrapper shall be a constexpr function if and only if the underlying call operation would satisfy the requirements of a constexpr function.</ins> A <i>simple call wrapper</i> is a forwarding call wrapper that is <i>Cpp17CopyConstructible</i> and <i>Cpp17CopyAssignable</i> and whose copy constructor, move constructor, copy assignment operator, and move assignment operator do not throw exceptions. [ <i>Note</i>: In a typical implementation forwarding call wrappers have an overloaded function call operator of the form
<pre class="codehilite"><code class="language-cpp">template&lt;class... UnBoundArgs&gt;
  </code><code><ins>constexpr</ins></code><code class="language-cpp"> R operator()(UnBoundArgs&amp;&amp;... unbound_args) </code><code><i>cv-qual</i>;</code></pre>
<i>— end note </i>]</p>
</blockquote>
<p>Add <code class="language-cpp">constexpr</code> to <code class="language-cpp">std::invoke()</code> in 19.14.4 [func.invoke]</p>
<blockquote><pre class="codehilite"><code class="language-cpp">template&lt;class F, class... Args>
</code>  <code><ins>constexpr</ins></code> <code class="language-cpp">invoke_result_t&lt;F, Args...> invoke(F&& f, Args&&... args)
    noexcept(is_nothrow_invocable_v&lt;F, Args...>);</code></pre></blockquote>

<p>Add <code class="language-cpp">constexpr</code> to <code class="language-cpp">std::reference_wrapper&lt;T&gt;</code> in 19.14.5 [refwrap]</p>
<blockquote><pre class="codehilite"><code class="language-cpp">namespace std {
  template&lt;class T> class reference_wrapper {
  public:
    // types
    using type = T;

    // construct/copy/destroy
    template&lt;class U>
    </code><code><ins>constexpr</ins></code> <code class="language-cpp">reference_wrapper(U&&) noexcept(see below );
    </code><code><ins>constexpr</ins></code> <code class="language-cpp">reference_wrapper(const reference_wrapper& x) noexcept;

    // assignment
    </code><code><ins>constexpr</ins></code> <code class="language-cpp">reference_wrapper& operator=(const reference_wrapper& x) noexcept;

    // access
    </code><code><ins>constexpr</ins></code> <code class="language-cpp">operator T& () const noexcept;
    </code><code><ins>constexpr</ins></code> <code class="language-cpp">T& get() const noexcept;

    // invocation
    template&lt;class... ArgTypes>
    </code><code><ins>constexpr</ins></code> <code class="language-cpp">invoke_result_t&lt;T&, ArgTypes...> operator()(ArgTypes&&...) const;
  };

  template&lt;class T>
  reference_wrapper(T&) -> reference_wrapper&lt;T>;
}</code></pre></blockquote>

<p>And its corresponding subsections, 19.14.5.1 [refwrap.const]</p>
<blockquote><pre class="codehilite"><code class="language-cpp">template&lt;class U>
</code><code><ins>constexpr</ins></code> <code class="language-cpp">reference_wrapper(U&& u) noexcept(see below );</code></pre>
[...]
<pre class="codehilite"><code class="language-cpp"></code><code><ins>constexpr</ins></code> <code class="language-cpp">reference_wrapper(const reference_wrapper& x) noexcept;</code></pre></blockquote>

<p>19.14.5.2 [refwrap.assign]</p>
<blockquote><pre class="codehilite"><code class="language-cpp"></code><code><ins>constexpr</ins></code> <code class="language-cpp">reference_wrapper& operator=(const reference_wrapper& x) noexcept;</code></pre></blockquote>

<p>19.14.5.3 [refwrap.access]</p>
<blockquote><pre class="codehilite"><code class="language-cpp"></code><code><ins>constexpr</ins></code> <code class="language-cpp">operator T& () const noexcept;</code></pre>
[...]
<pre class="codehilite"><code class="language-cpp"></code><code><ins>constexpr</ins></code> <code class="language-cpp">T& get() const noexcept;</code></pre></blockquote>

<p>19.14.5.4 [refwrap.invoke]</p>
<blockquote><pre class="codehilite"><code class="language-cpp">template&lt;class... ArgTypes>
  </code><code><ins>constexpr</ins></code> <code class="language-cpp">invoke_result_t&lt;T&, ArgTypes...>
    operator()(ArgTypes&&... args) const;</code></pre></blockquote>

<p>and its helper functions, 19.14.5.5 [refwrap.helpers]</p>
<blockquote><pre class="codehilite"><code class="language-cpp">template&lt;class T> </code><code><ins>constexpr</ins></code> <code class="language-cpp">reference_wrapper&lt;T> ref(T& t) noexcept;</code></pre>
<span style="margin-left:2em;" /><i>1 Returns</i>: <code class="language-cpp">reference_wrapper&lt;T>(t)</code>.
<pre class="codehilite"><code class="language-cpp">template&lt;class T> </code><code><ins>constexpr</ins></code> <code class="language-cpp">reference_wrapper&lt;T> ref(reference_wrapper&lt;T> t) noexcept;</code></pre>
<span style="margin-left:2em;" /><i>2 Returns</i>: <code class="language-cpp">ref(t.get())</code>.
<pre class="codehilite"><code class="language-cpp">template&lt;class T> </code><code><ins>constexpr</ins></code> <code class="language-cpp">reference_wrapper&lt;const T> cref(const T& t) noexcept;</code></pre>
<span style="margin-left:2em;" /><i>3 Returns</i>: <code class="language-cpp">reference_wrapper&lt;const T>(t)</code>.
<pre class="codehilite"><code class="language-cpp">template&lt;class T> </code><code><ins>constexpr</ins></code> <code class="language-cpp">reference_wrapper&lt;const T> cref(reference_wrapper&lt;T> t) noexcept;</code></pre>
<span style="margin-left:2em;" /><i>4 Returns</i>: <code class="language-cpp">cref(t.get())</code>.</blockquote>

<p>Add <code class="language-cpp">constexpr</code> to <code class="language-cpp">std::not_fn</code> in 19.14.11 [func.not_fn]</p>
<blockquote><pre class="codehilite"><code class="language-cpp">template&lt;class F> </code><code><ins>constexpr</ins></code> <i>unspecified</i> <code class="language-cpp">not_fn(F&& f);</code></pre>
<span style="margin-left:2em;" /><i>1 Effects</i>: Equivalent to: <pre class="inline"><code class="language-cpp">return </code><code><i>call_wrapper</i></code><code class="language-cpp">(std::forward&lt;F>(f));</code></pre> where <code><i>call_wrapper</i></code> is an exposition only class defined as follows:
<pre class="codehilite" style="margin-left:2em"><code class="language-cpp">class </code><code><i>call_wrapper</i></code><code class="language-cpp"> {
  using FD = decay_t&lt;F>;
  FD fd;

  explicit </code><code><ins>constexpr</ins> <i>call_wrapper</i></code><code class="language-cpp">(F&& f);  
public:
  </code><code><ins>constexpr</ins> <i>call_wrapper</i>(<i>call_wrapper</i></code><code class="language-cpp"> &&) = default;
  </code><code><ins>constexpr</ins> <i>call_wrapper</i>(</code><code class="language-cpp">const</code><code> <i>call_wrapper</i></code><code class="language-cpp">&) = default;

  template&lt;class... Args>
    </code><code><ins>constexpr</ins></code><code class="language-cpp"> auto operator()(Args&&...) &
      -> decltype(!declval&lt;invoke_result_t&lt;FD&, Args...>>());

  template&lt;class... Args>
    </code><code><ins>constexpr</ins></code><code class="language-cpp"> auto operator()(Args&&...) const&
      -> decltype(!declval&lt;invoke_result_t&lt;const FD&, Args...>>());

  template&lt;class... Args>
    </code><code><ins>constexpr</ins></code><code class="language-cpp"> auto operator()(Args&&...) &&
      -> decltype(!declval&lt;invoke_result_t&lt;FD, Args...>>());

  template&lt;class... Args>
    </code><code><ins>constexpr</ins></code><code class="language-cpp"> auto operator()(Args&&...) const&&
      -> decltype(!declval&lt;invoke_result_t&lt;const FD, Args...>>());
};</code></pre>

<pre class="codehilite"><code class="language-cpp">explicit </code><code><ins>constexpr</ins></code> <code class="language-cpp"><i>call_wrapper</i>(F&& f);</code></pre>
[...]
<pre class="codehilite"><code class="language-cpp">template&lt;class... Args>
  </code><code><ins>constexpr</ins></code><code class="language-cpp"> auto operator()(Args&&...) &
    -> decltype(!declval&lt;invoke_result_t&lt;FD&, Args...>>());

template&lt;class... Args>
  </code><code><ins>constexpr</ins></code><code class="language-cpp"> auto operator()(Args&&...) const&
    -> decltype(!declval&lt;invoke_result_t&lt;const FD&, Args...>>());</code></pre>
<span style="margin-left:2em;" /><i>5 Effects</i>: Equivalent to: <pre class="codehilite" style="margin-left:3em"><code class="language-cpp">return !</code><code><i>INVOKE</i></code><code class="language-cpp">(fd, std::forward&lt;Args>(args)...); // see 19.14.3</code></pre>

<pre class="codehilite"><code class="language-cpp">template&lt;class... Args>
  </code><code><ins>constexpr</ins></code><code class="language-cpp"> auto operator()(Args&&...) &&
    -> decltype(!declval&lt;invoke_result_t&lt;FD&, Args...>>());

template&lt;class... Args>
  </code><code><ins>constexpr</ins></code><code class="language-cpp"> auto operator()(Args&&...) const&&
    -> decltype(!declval&lt;invoke_result_t&lt;const FD&, Args...>>());</code></pre>
<span style="margin-left:2em;" /><i>6 Effects</i>: Equivalent to: <pre class="codehilite" style="margin-left:3em"><code class="language-cpp">return !</code><code><i>INVOKE</i></code><code class="language-cpp">(std::move(fd), std::forward&lt;Args>(args)...); // see 19.14.3</code></pre>
</blockquote>

<p>Add <code class="language-cpp">constexpr</code> to <code class="language-cpp">std::bind()</code> in 19.14.12.3 [func.bind.bind]</p>
<blockquote><pre class="codehilite"><code class="language-cpp">template&lt;class F, class... BoundArgs>
  </code><code><ins>constexpr</ins> <i>unspecified</i></code><code class="language-cpp"> bind(F&& f, BoundArgs&&... bound_args);</code></pre>
[...]
<pre class="codehilite"><code class="language-cpp">template&lt;class R, class F, class... BoundArgs>
  </code><code><ins>constexpr</ins> <i>unspecified</i></code><code class="language-cpp"> bind(F&& f, BoundArgs&&... bound_args);</code></pre></blockquote>

<p>Add <code class="language-cpp">constexpr</code> to <code class="language-cpp">std::mem_fn()</code> in 19.14.13 [func.memfn]</p>
<blockquote><pre class="codehilite"><code class="language-cpp">template&lt;class R, class T> </code><code><ins>constexpr</ins> <i>unspecified</i> </code><code class="language-cpp">mem_fn(R T::* pm) noexcept;</code></pre></blockquote>

<h2 id="acknowledgements">4. Acknowledgements<a class="self-link" href="#acknowledgements"></a></h2>
<p>Thanks to Casey Carter and Agustín Bergé for going over the history of issues surrounding <code class="language-cpp">constexpr invoke</code> and suggesting that this proposal be written. Thanks to Tomasz Kamiński and Tim Song for help on the wording.</p>
<h2 id="references">5. References<a class="self-link" href="#references"></a></h2><ul><li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1581">[CWG1581]</a><span style="margin-left: 5px;">"When are constexpr member functions defined?" by Richard Smith, 2012-10-29</span></li><li><a href="https://cplusplus.github.io/LWG/issue2894">[LWG2894]</a><span style="margin-left: 5px;">"The function template std::apply() is required to be constexpr, but std::invoke() isn't" by Great Britain, 2017-08-01</span></li><li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0859r0.html">[P0859]</a><span style="margin-left: 5px;">"Core Issue 1581: When are constexpr member functions defined?" by Richard Smith, 2017-11-09</span></li></ul>
</html>