<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>The Mothership Has Landed  Adding <=> to the Library</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.ins {
	border-left: 4px solid #00a000;
	padding: 0 15px;
	color: #00a000;
}
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|concept|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|requires|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: P1614R0 <br />
Date: 2019-03-14 <br />
Audience: LWG <br />
Reply-To: Barry Revzin, barry dot revzin at gmail dot com <br />
</address>
<hr /><h1 align=center><p>The Mothership Has Landed <br /> Adding <code class="language-cpp">&lt;=&gt;</code> to the Library</p></h1>
<h2>Contents</h2>
<div class="toc">
<ol>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#known-behavioral-changes">Known behavioral changes</a><ol>
<li><a href="#was-well-formed-now-ill-formed">Was well-formed, now ill-formed</a></li>
<li><a href="#was-ill-formed-now-well-formed">Was ill-formed, now well-formed</a></li>
</ol>
</li>
<li><a href="#acknowledgments">Acknowledgments</a></li>
<li><a href="#wording">Wording</a><ol>
<li><a href="#clause-16-library-introduction">Clause 16: Library Introduction</a></li>
<li><a href="#clause-17-language-support-library">Clause 17: Language support library</a></li>
<li><a href="#clause-18-concepts-library">Clause 18: Concepts Library</a></li>
<li><a href="#clause-19-diagnostics-library">Clause 19: Diagnostics Library</a></li>
<li><a href="#clause-20-general-utilities-library">Clause 20: General utilities library</a></li>
<li><a href="#clause-21-strings-library">Clause 21: Strings library</a></li>
<li><a href="#clause-22-containers-library">Clause 22: Containers library</a></li>
<li><a href="#clause-23-iterators-library">Clause 23: Iterators library</a></li>
<li><a href="#clause-24-ranges-library">Clause 24: Ranges library</a></li>
<li><a href="#clause-25-algorithms-library">Clause 25: Algorithms library</a></li>
<li><a href="#clause-26-numerics-library">Clause 26: Numerics library</a></li>
<li><a href="#clause-27-time-library">Clause 27: Time library</a></li>
<li><a href="#clause-28-localization-library">Clause 28: Localization library</a></li>
<li><a href="#clause-29-inputoutput-library">Clause 29: Input/output library</a></li>
<li><a href="#clause-30-regular-expressions-library">Clause 30: Regular expressions library</a></li>
<li><a href="#clause-31-atomic-operations-library">Clause 31: Atomic operations library</a></li>
<li><a href="#clause-32-thread-support-library">Clause 32: Thread support library</a></li>
</ol>
</li>
<li><a href="#references">References</a></li>
</ol>
</div>

<h2 id="introduction">1. Introduction<a class="self-link" href="#introduction"></a></h2>
<p>The work of integrating <code class="language-cpp">operator&lt;=&gt;</code> into the library has been performed by multiple different papers, each addressing a different aspect of the integration. In the interest of streamlining review by the Library Working Group, the wording has been combined into a single paper. This is that paper.</p>
<p>In San Diego and Kona, several papers were approved by LEWG adding functionality to the library related to comparisons. What follows is the list of those papers, in alphabetical order, with a brief description of what those papers are. The complete motivation and design rationale for each can be found within the papers themselves.</p>
<ul>
<li><a href="https://wg21.link/p0790r2" title="Effect of operator&lt;=&gt; on the C++ Standard Library">P0790R2</a> - adding <code class="language-cpp">operator&lt;=&gt;</code> to the standard library types whose behavior is not dependent on a template parameter.</li>
<li><a href="https://wg21.link/p0891r2" title="Make strong_order a Customization Point!">P0891R2</a> - making the <code class="language-cpp">XXX_order</code> algorithms customization points and introducing <code class="language-cpp">compare_XXX_order_fallback</code> algorithms that preferentially invoke the former algorithm and fallback to synthesizing an ordering from <code class="language-cpp">==</code> and <code class="language-cpp">&lt;</code> (using the rules from <a href="https://wg21.link/p1186r1" title="When do you actually use &lt;=&gt;?">P1186R1</a>).</li>
<li><a href="https://wg21.link/p1154r1" title="Type traits for structural comparison">P1154R1</a> - adding the type trait <code class="language-cpp">has_strong_structural_equality&lt;T&gt;</code> (useful to check if a type can be used as a non-type template parameter).</li>
<li><a href="https://wg21.link/p1188r0" title="Library utilities for &lt;=&gt;">P1188R0</a> - adding the type trait <code class="language-cpp">compare_three_way_result&lt;T&gt;</code>, the concepts <code class="language-cpp">ThreeWayComparable&lt;T&gt;</code> and <code class="language-cpp">ThreeWayComparableWith&lt;T,U&gt;</code>, removing the algorithm <code class="language-cpp">compare_3way</code> and replacing it with a function comparison object <code class="language-cpp">compare_three_way</code> (i.e. the <code class="language-cpp">&lt;=&gt;</code> version of <code class="language-cpp">std::ranges::less</code>).</li>
<li><a href="https://wg21.link/p1189r0" title="Add &lt;=&gt; to Library">P1189R0</a> - adding <code class="language-cpp">operator&lt;=&gt;</code> to the standard library types whose behavior is dependent on a template parameter, removing those equality operators made redundant by <a href="https://wg21.link/p1185r1" title="&lt;=&gt; != ==">P1185R1</a> and defaulting <code class="language-cpp">operator==</code> where appropriate.</li>
<li><a href="https://wg21.link/p1191r0" title="Adding operator&lt;=&gt; to types that are not currently comparable">P1191R0</a> - adding equality to several previously incomparable standard library types.</li>
<li><a href="https://wg21.link/p1295r0" title="Spaceship library update">P1295R0</a> - adding equality and <code class="language-cpp">common_type</code> for the comparison categories.</li>
<li><a href="https://wg21.link/p1380r1" title="Ambiguity and Insecurities with Three-Way Comparison">P1380R1</a> - extending the floating point customization points for <code class="language-cpp">strong_order</code> and <code class="language-cpp">weak_order</code>.</li>
</ul>
<p>LEWG's unanimous preference was that <code class="language-cpp">operator&lt;=&gt;</code>s be declared as hidden friends.</p>
<h2 id="known-behavioral-changes">2. Known behavioral changes<a class="self-link" href="#known-behavioral-changes"></a></h2>
<p>There are a few things that will change behavior as a result of all these papers and the chosen direction for declaring operators as hidden friends. </p>
<h3 id="was-well-formed-now-ill-formed">2.1. Was well-formed, now ill-formed<a class="self-link" href="#was-well-formed-now-ill-formed"></a></h3>
<p>For the preexisting non-member, non-template comparison operators, any comparison that relies on finding the operator in <code class="language-cpp">std</code> with regular unqualified lookup will fail:</p>
<pre class="codehilite"><code class="language-cpp">using namespace std;
struct X { operator error_code() const; };
X{} == X{};          // ok in C++17, ill-formed with this change
X{} == error_code{}; // ok</code></pre>


<p>Here is a more subtle example, reproduced from the LLVM codebase:</p>
<pre class="codehilite" data-line="8"><code class="language-cpp">struct StringRef {
    StringRef(std::string const&amp;); // NB: non-explicit
    operator std::string() const;  // NB: non-explicit
};
bool operator==(StringRef, StringRef);

bool f(StringRef a, std::string b) {
    return a == b; // (*)
}</code></pre>


<p>In C++17, the marked line is well-formed. The <code class="language-cpp">operator==</code> for <code class="language-cpp">basic_string</code> is a non-member function template, and so would not be considered a candidate; the only viable candidate is the <code class="language-cpp">operator==</code> taking two <code class="language-cpp">StringRef</code>s. With the proposed changes, the <code class="language-cpp">operator==</code> for <code class="language-cpp">basic_string</code> becomes a non-member hidden friend, <em>non-template</em>, which makes it a candidate (converting <code class="language-cpp">a</code> to a <code class="language-cpp">string</code>). That candidate is ambiguous with the <code class="language-cpp">operator==(StringRef, StringRef)</code> candidate - each requires a conversion in one argument, so the call becomes ill-formed.</p>
<h3 id="was-ill-formed-now-well-formed">2.2. Was ill-formed, now well-formed<a class="self-link" href="#was-ill-formed-now-well-formed"></a></h3>
<pre class="codehilite" data-line="2"><code class="language-cpp">bool is42(std::variant&lt;int, std::string&gt; const&amp; v) {
    return v == 42; // (*)
}</code></pre>


<p>In C++17, the <code class="language-cpp">operator==</code> for <code class="language-cpp">variant</code> is a non-member function template and is thus not a viable candidate for the marked line. That check is ill-formed. With the proposed changes, the <code class="language-cpp">operator==</code> for <code class="language-cpp">variant</code> becomes a non-member hidden friend, <em>non-template</em>, which makes it a candidate (converting <code class="language-cpp">42</code> to a <code class="language-cpp">variant&lt;int, string&gt;</code>). This is arguably a fix, since both <code class="language-cpp">variant&lt;int, string&gt; v = 42;</code> and <code class="language-cpp">v = 42;</code> are already well-formed, so it is surely reasonable that <code class="language-cpp">v == 42</code> is as well.</p>
<h2 id="acknowledgments">3. Acknowledgments<a class="self-link" href="#acknowledgments"></a></h2>
<p>Thank you to Casey Carter for the tremendous wording review.</p>
<h2 id="wording">4. Wording<a class="self-link" href="#wording"></a></h2>
<h3 id="clause-16-library-introduction">4.1. Clause 16: Library Introduction<a class="self-link" href="#clause-16-library-introduction"></a></h3>
<p>Change 16.4.2.1/2 [expos.only.func]:</p>
<blockquote>
<p>The following <del>function is</del> <ins>are</ins> defined for exposition only to aid in the specification of the library:</p>
</blockquote>
<p>and append:</p>
<blockquote><pre><code class="language-cpp">constexpr auto </code><code><i>synth-3way</i></code><code class="language-cpp"> =
  []&lt;class T, class U&gt;(const T& t, const U& u)
    requires requires {
      { t < u } -> bool;
      { u < t } -> bool;
    }
  {
    if constexpr (ThreeWayComparableWith&lt;T, U&gt;) {
      return t <=> u;
    } else {
      if (t < u) return weak_ordering::less;
      if (u < t) return weak_ordering::greater;
      return weak_ordering::equivalent;
    }
  };

template&lt;class T, class U=T&gt;
using </code><code><i>synth-3way-result</i></code><code class="language-cpp"> = decltype(</code><code><i>synth-3way</i></code><code class="language-cpp">(declval&lt;T&&gt;(), declval&lt;U&&gt;()));</code></pre></blockquote>

<p>Remove 16.4.2.3 [operators], which begins:</p>
<blockquote>
<p><del>In this library, whenever a declaration is provided for an <code class="language-cpp">operator!=</code>, <code class="language-cpp">operator&gt;</code>, <code class="language-cpp">operator&lt;=</code>, or <code class="language-cpp">operator&gt;=</code> for a type <code class="language-cpp">T</code>, its requirements and semantics are as follows, unless explicitly specified otherwise.</del></p>
</blockquote>
<p>Add a clause to 16.5.5 [conforming], probably after 16.5.5.4 [global.functions]. Not strictly related to <code class="language-cpp">&lt;=&gt;</code> as a whole, but it's a requirement that's currently missing and needs to be added somewhere. See also P1601.</p>
<blockquote>
<p><strong>16.5.5.x Hidden friend functions [conforming.hidden.friend]</strong></p>
<p>An implementation shall not provide any additional out-of-class declarations or redeclarations for any non-member function specified as a non-member <code class="language-cpp">friend</code> and defined within the body of a class. [ <em>Note</em>: The intent is that such functions are to be found via argument-dependent lookup only. <em>-end note</em> ]</p>
</blockquote>
<h3 id="clause-17-language-support-library">4.2. Clause 17: Language support library<a class="self-link" href="#clause-17-language-support-library"></a></h3>
<p>Added: <code class="language-cpp">compare_three_way_result</code>, concepts <code class="language-cpp">ThreeWayComparable</code> and <code class="language-cpp">ThreeWayComparableWith</code>, <code class="language-cpp">compare_three_way</code> and <code class="language-cpp">compare_XXX_order_fallback</code></p>
<p>Changed operators for: <code class="language-cpp">type_info</code></p>
<p>Respecified: <code class="language-cpp">strong_order()</code>, <code class="language-cpp">weak_order()</code>, and <code class="language-cpp">partial_order()</code></p>
<p>Removed: <code class="language-cpp">compare_3way()</code>, <code class="language-cpp">strong_equal()</code>, and <code class="language-cpp">weak_equal()</code></p>
<p>In 17.7.2 [type.info], remove <code class="language-cpp">operator!=</code>:</p>
<blockquote><pre><code>namespace std {
  class type_info {
  public:
    virtual ~type_info();
    bool operator==(const type_info& rhs) const noexcept;
    <del>bool operator!=(const type_info& rhs) const noexcept;</del>
    bool before(const type_info& rhs) const noexcept;
    size_t hash_code() const noexcept;
    const char* name() const noexcept;
    type_info(const type_info& rhs) = delete; // cannot be copied
    type_info& operator=(const type_info& rhs) = delete; // cannot be copied
  };
}</code></pre></blockquote>

<p>and</p>
<blockquote>
<p><pre><code>bool operator==(const type_info&amp; rhs) const noexcept;</code></pre>
<em>Effects</em>: Compares the current object with rhs.<br />
<em>Returns</em>: <code class="language-cpp">true</code> if the two values describe the same type.<br />
<pre><code><del>bool operator!=(const type_info&amp; rhs) const noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(*this == rhs)</code>.</del></p>
</blockquote>
<p>Add into 17.11.1 [compare.syn]:</p>
<blockquote><pre><code>namespace std {
  // [cmp.categories], comparison category types
  class weak_equality;
  class strong_equality;
  class partial_ordering;
  class weak_ordering;
  class strong_ordering;

  // named comparison functions
  constexpr bool is_eq  (weak_equality cmp) noexcept    { return cmp == 0; }
  constexpr bool is_neq (weak_equality cmp) noexcept    { return cmp != 0; }
  constexpr bool is_lt  (partial_ordering cmp) noexcept { return cmp < 0; }
  constexpr bool is_lteq(partial_ordering cmp) noexcept { return cmp <= 0; }
  constexpr bool is_gt  (partial_ordering cmp) noexcept { return cmp > 0; }
  constexpr bool is_gteq(partial_ordering cmp) noexcept { return cmp >= 0; }

  <ins>// common_type specializations</ins>
  <ins>template&lt;&gt; struct common_type&lt;strong_equality, partial_ordering&gt;</ins>
  <ins>  { using type = weak_equality; };</ins>
  <ins>template&lt;&gt; struct common_type&lt;partial_ordering, strong_equality&gt;</ins>
  <ins>  { using type = weak_equality; };</ins>
  <ins>template&lt;&gt; struct common_type&lt;strong_equality, weak_ordering&gt;</ins>
  <ins>  { using type = weak_equality; };</ins>
  <ins>template&lt;&gt; struct common_type&lt;weak_ordering, strong_equality&gt;</ins>
  <ins>  { using type = weak_equality; };</ins>

  // [cmp.common], common comparison category type  
  template&lt;class... Ts&gt;
  struct common_comparison_category {
    using type = see below;
  };
  template&lt;class... Ts&gt;
    using common_comparison_category_t = typename common_comparison_category&lt;Ts...&gt;::type;  

  <ins>// [cmp.concept], concept ThreeWayComparable</ins>
  <ins>template&lt;class T, class Cat = partial_ordering&gt;</ins>
    <ins>concept ThreeWayComparable = <i>see below</i>;</ins>
  <ins>template&lt;class T, class U, class Cat = partial_ordering&gt;</ins>
    <ins>concept ThreeWayComparableWith = <i>see below</i>;</ins>

  <ins>// [cmp.result], spaceship invocation result</ins>
  <ins>template&lt;class T, class U = T&gt; struct compare_three_way_result;</ins>

  <ins>template&lt;class T, class U = T&gt;</ins>
  <ins>  using compare_three_way_result_t = typename compare_three_way_result&lt;T, U&gt;::type;</ins>

  <ins>// [cmp.object], spaceship object</ins>
  <ins>struct compare_three_way;</ins>

  // [cmp.alg], comparison algorithms
  <del>template&lt;class T&gt; constexpr strong_ordering strong_order(const T& a, const T& b);</del>
  <del>template&lt;class T&gt; constexpr weak_ordering weak_order(const T& a, const T& b);</del>
  <del>template&lt;class T&gt; constexpr partial_ordering partial_order(const T& a, const T& b);</del>
  <del>template&lt;class T&gt; constexpr strong_equality strong_equal(const T& a, const T& b);</del>
  <del>template&lt;class T&gt; constexpr weak_equality weak_equal(const T& a, const T& b);</del>
  <ins>inline namespace <i>unspecified</i> {</ins>
    <ins>inline constexpr <i>unspecified</i> strong_order = <i>unspecified</i>;</ins>
    <ins>inline constexpr <i>unspecified</i> weak_order = <i>unspecified</i>;</ins>
    <ins>inline constexpr <i>unspecified</i> partial_order = <i>unspecified</i>;</ins>
    <ins>inline constexpr <i>unspecified</i> compare_strong_order_fallback = <i>unspecified</i>;</ins>
    <ins>inline constexpr <i>unspecified</i> compare_weak_order_fallback = <i>unspecified</i>;</ins>
    <ins>inline constexpr <i>unspecified</i> compare_partial_order_fallback = <i>unspecified</i>;</ins>
  <ins>}</ins>
}</code></pre></blockquote>

<p>Change 17.11.2.2 [cmp.weakeq]:</p>
<blockquote><pre><code>namespace std {
  class weak_equality {
    int value;  // exposition only
    [...]

    // comparisons
    friend constexpr bool operator==(weak_equality v, <i>unspecified</i>) noexcept<del>;</del>
    <ins> { return v.value == 0; }</ins>
    <del>friend constexpr bool operator!=(weak_equality v, <i>unspecified</i>) noexcept;</del>
    <del>friend constexpr bool operator==(<i>unspecified</i>, weak_equality v) noexcept;</del>
    <Del>friend constexpr bool operator!=(<i>unspecified</i>, weak_equality v) noexcept;</del>
    <ins>friend constexpr bool operator==(weak_equality v, weak_equality w) noexcept = default;</ins>
    friend constexpr weak_equality operator<=>(weak_equality v, <i>unspecified</i>) noexcept<del>;</del>
    <ins> { return v; }</ins>
    friend constexpr weak_equality operator<=>(<i>unspecified</i>, weak_equality v) noexcept<del>;</del>
    <ins> { return v; }</ins>
  };

  // valid values' definitions
  inline constexpr weak_equality weak_equality::equivalent(eq::equivalent);
  inline constexpr weak_equality weak_equality::nonequivalent(eq::nonequivalent);
}</code></pre></blockquote>

<p>Remove the rest of the clause (now defined inline):</p>
<blockquote>
<p><pre><code><del>constexpr bool operator==(weak_equality v, unspecified) noexcept;
constexpr bool operator==(unspecified, weak_equality v) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">v.value == 0</code>.</del>
<pre><code><del>constexpr bool operator!=(weak_equality v, unspecified) noexcept;
constexpr bool operator!=(unspecified, weak_equality v) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">v.value != 0</code>.</del>
<pre><code><del>constexpr weak_equality operator&lt;=&gt;(weak_equality v, unspecified) noexcept;
constexpr weak_equality operator&lt;=&gt;(unspecified, weak_equality v) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">v</code>.</del></p>
</blockquote>
<p>Change 17.11.2.3 [cmp.strongeq]:</p>
<blockquote><pre><code>namespace std {
  class strong_equality {
    int value;  // exposition only
    [...]

    // comparisons
    friend constexpr bool operator==(strong_equality v, <i>unspecified</i>) noexcept<del>;</del>
    <ins>  { return v.value == 0; }</ins>
    <del>friend constexpr bool operator!=(strong_equality v, <i>unspecified</i>) noexcept;</del>
    <del>friend constexpr bool operator==(<i>unspecified</i>, strong_equality v) noexcept;</del>
    <del>friend constexpr bool operator!=(<i>unspecified</i>, strong_equality v) noexcept;</del>
    <ins>friend constexpr bool operator==(strong_equality v, strong_equality w) noexcept = default;</ins>
    friend constexpr strong_equality operator&lt;=&gt;(strong_equality v, <i>unspecified</i>) noexcept<del>;</del>
    <ins>  { return v; }</ins>
    friend constexpr strong_equality operator&lt;=&gt;(unspecified, strong_equality v) noexcept<del>;</del>
    <ins>  { return v; }</ins>
  };

  // valid values' definitions
  inline constexpr strong_equality strong_equality::equal(eq::equal);
  inline constexpr strong_equality strong_equality::nonequal(eq::nonequal);
  inline constexpr strong_equality strong_equality::equivalent(eq::equivalent);
  inline constexpr strong_equality strong_equality::nonequivalent(eq::nonequivalent);
}</code></pre></blockquote>

<p>Remove most of the rest of the clause:</p>
<blockquote>
<p><pre><code>constexpr operator weak_equality() const noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">value == 0 ? weak_equality::equivalent : weak_equality::nonequivalent</code>.
<pre><code><del>constexpr bool operator==(strong_equality v, unspecified) noexcept;
constexpr bool operator==(unspecified, strong_equality v) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">v.value == 0</code>.</del>
<pre><code><del>constexpr bool operator!=(strong_equality v, unspecified) noexcept;
constexpr bool operator!=(unspecified, strong_equality v) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">v.value != 0</code>.</del>
<pre><code><del>constexpr strong_equality operator&lt;=&gt;(strong_equality v, unspecified) noexcept;
constexpr strong_equality operator&lt;=&gt;(unspecified, strong_equality v) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">v</code>.</del></p>
</blockquote>
<p>Change 17.11.2.4 [cmp.partialord]:</p>
<blockquote><pre><code>namespace std {
  class partial_ordering {
    int value;          // exposition only
    bool is_ordered;    // exposition only

    [...]
    // conversion
    constexpr operator weak_equality() const noexcept;

    // comparisons
    friend constexpr bool operator==(partial_ordering v, <i>unspecified</i>) noexcept;
    <del>friend constexpr bool operator!=(partial_ordering v, <i>unspecified</i>) noexcept;</del>
    <ins>friend constexpr bool operator==(partial_ordering v, partial_ordering w) noexcept = default;</ins>
    friend constexpr bool operator&lt; (partial_ordering v, <i>unspecified</i>) noexcept;
    friend constexpr bool operator&gt; (partial_ordering v, <i>unspecified</i>) noexcept;
    friend constexpr bool operator&lt;=(partial_ordering v, <i>unspecified</i>) noexcept;
    friend constexpr bool operator&gt;=(partial_ordering v, <i>unspecified</i>) noexcept;
    <del>friend constexpr bool operator==(<i>unspecified</i>, partial_ordering v) noexcept;</del>
    <del>friend constexpr bool operator!=(<i>unspecified</i>, partial_ordering v) noexcept;</del>
    friend constexpr bool operator&lt; (<i>unspecified</i>, partial_ordering v) noexcept;
    friend constexpr bool operator&gt; (<i>unspecified</i>, partial_ordering v) noexcept;
    friend constexpr bool operator&lt;=(<i>unspecified</i>, partial_ordering v) noexcept;
    friend constexpr bool operator&gt;=(<i>unspecified</i>, partial_ordering v) noexcept;
    friend constexpr partial_ordering operator&lt;=&gt;(partial_ordering v, <i>unspecified</i>) noexcept;
    friend constexpr partial_ordering operator&lt;=&gt;(<i>unspecified</i>, partial_ordering v) noexcept;
  };

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

<p>Remove just the extra <code class="language-cpp">==</code> and <code class="language-cpp">!=</code> operators in 17.11.2.4 [cmp.partialord]/3 and 4:</p>
<blockquote>
<p><pre><code>constexpr bool operator==(partial_ordering v, <i>unspecified</i>) noexcept;
constexpr bool operator&lt; (partial_ordering v, <i>unspecified</i>) noexcept;
constexpr bool operator&gt; (partial_ordering v, <i>unspecified</i>) noexcept;
constexpr bool operator&lt;=(partial_ordering v, <i>unspecified</i>) noexcept;
constexpr bool operator&gt;=(partial_ordering v, <i>unspecified</i>) noexcept;</code></pre>
<em>Returns</em>: For <code class="language-cpp">operator@</code>, <code class="language-cpp">v.is_ordered &amp;&amp; v.value @ 0</code>.
<pre><code><del>constexpr bool operator==(<i>unspecified</i>, partial_ordering v) noexcept;</del>
constexpr bool operator&lt; (<i>unspecified</i>, partial_ordering v) noexcept;
constexpr bool operator&gt; (<i>unspecified</i>, partial_ordering v) noexcept;
constexpr bool operator&lt;=(<i>unspecified</i>, partial_ordering v) noexcept;
constexpr bool operator&gt;=(<i>unspecified</i>, partial_ordering v) noexcept;</code></pre>
<em>Returns</em>: For <code class="language-cpp">operator@</code>, <code class="language-cpp">v.is_ordered &amp;&amp; 0 @ v.value</code>.
<pre><code><del>constexpr bool operator!=(partial_ordering v, <i>unspecified</i>) noexcept;
constexpr bool operator!=(<i>unspecified</i>, partial_ordering v) noexcept;</del></code></pre>
<del><em>Returns</em>: For <code class="language-cpp">operator@</code>, <code class="language-cpp">!v.is_ordered || v.value != 0</code>.</del></p>
</blockquote>
<p>Change 17.11.2.5 [cmp.weakord]:</p>
<blockquote><pre><code>namespace std {
  class weak_ordering {
    int value;  // exposition only

    [...]
    // comparisons
    friend constexpr bool operator==(weak_ordering v, <i>unspecified</i>) noexcept;
    <ins>friend constexpr bool operator==(weak_ordering v, weak_ordering w) noexcept = default;</ins>
    <del>friend constexpr bool operator!=(weak_ordering v, <i>unspecified</i>) noexcept;</del>
    friend constexpr bool operator&lt; (weak_ordering v, <i>unspecified</i>) noexcept;
    friend constexpr bool operator&gt; (weak_ordering v, <i>unspecified</i>) noexcept;
    friend constexpr bool operator&lt;=(weak_ordering v, <i>unspecified</i>) noexcept;
    friend constexpr bool operator&gt;=(weak_ordering v, <i>unspecified</i>) noexcept;
    <del>friend constexpr bool operator==(<i>unspecified</i>, weak_ordering v) noexcept;</del>
    <del>friend constexpr bool operator!=(<i>unspecified</i>, weak_ordering v) noexcept;</del>
    friend constexpr bool operator&lt; (<i>unspecified</i>, weak_ordering v) noexcept;
    friend constexpr bool operator&gt; (<i>unspecified</i>, weak_ordering v) noexcept;
    friend constexpr bool operator&lt;=(<i>unspecified</i>, weak_ordering v) noexcept;
    friend constexpr bool operator&gt;=(<i>unspecified</i>, weak_ordering v) noexcept;
    friend constexpr weak_ordering operator&lt;=&gt;(weak_ordering v, <i>unspecified</i>) noexcept;
    friend constexpr weak_ordering operator&lt;=&gt;(<i>unspecified</i>, weak_ordering v) noexcept;
  };

  [...]
};</code></pre></blockquote>

<p>Remove just the extra <code class="language-cpp">==</code> and <code class="language-cpp">!=</code> operators from 17.11.2.5 [cmp.weakord]/4 and /5:</p>
<blockquote>
<p><pre><code>constexpr bool operator==(weak_ordering v, <i>unspecified</i>) noexcept;
<del>constexpr bool operator!=(weak_ordering v, <i>unspecified</i>) noexcept;</del>
constexpr bool operator&lt; (weak_ordering v, <i>unspecified</i>) noexcept;
constexpr bool operator&gt; (weak_ordering v, <i>unspecified</i>) noexcept;
constexpr bool operator&lt;=(weak_ordering v, <i>unspecified</i>) noexcept;
constexpr bool operator&gt;=(weak_ordering v, <i>unspecified</i>) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">v.value @ 0</code> for <code class="language-cpp">operator@</code>.
<pre><code><del>constexpr bool operator==(<i>unspecified</i>, weak_ordering v) noexcept;</del>
<del>constexpr bool operator!=(<i>unspecified</i>, weak_ordering v) noexcept;</del>
constexpr bool operator&lt; (<i>unspecified</i>, weak_ordering v) noexcept;
constexpr bool operator&gt; (<i>unspecified</i>, weak_ordering v) noexcept;
constexpr bool operator&lt;=(<i>unspecified</i>, weak_ordering v) noexcept;
constexpr bool operator&gt;=(<i>unspecified</i>, weak_ordering v) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">0 @ v.value</code> for <code class="language-cpp">operator@</code>.</p>
</blockquote>
<p>Change 17.11.2.6 [cmp.strongord]:</p>
<blockquote><pre><code>namespace std {
  class strong_ordering {
    int value;  // exposition only

    [...]

    // comparisons
    friend constexpr bool operator==(strong_ordering v, <i>unspecified</i>) noexcept;
    <ins>friend constexpr bool operator==(strong_ordering v, strong_ordering w) noexcept = default;</ins>
    <del>friend constexpr bool operator!=(strong_ordering v, <i>unspecified</i>) noexcept;</del>
    friend constexpr bool operator&lt; (strong_ordering v, <i>unspecified</i>) noexcept;
    friend constexpr bool operator&gt; (strong_ordering v, <i>unspecified</i>) noexcept;
    friend constexpr bool operator&lt;=(strong_ordering v, <i>unspecified</i>) noexcept;
    friend constexpr bool operator&gt;=(strong_ordering v, <i>unspecified</i>) noexcept;
    <del>friend constexpr bool operator==(<i>unspecified</i>, strong_ordering v) noexcept;</del>
    <del>friend constexpr bool operator!=(<i>unspecified</i>, strong_ordering v) noexcept;</del>
    friend constexpr bool operator&lt; (<i>unspecified</i>, strong_ordering v) noexcept;
    friend constexpr bool operator&gt; (<i>unspecified</i>, strong_ordering v) noexcept;
    friend constexpr bool operator&lt;=(<i>unspecified</i>, strong_ordering v) noexcept;
    friend constexpr bool operator&gt;=(<i>unspecified</i>, strong_ordering v) noexcept;
    friend constexpr strong_ordering operator&lt;=&gt;(strong_ordering v, <i>unspecified</i>) noexcept;
    friend constexpr strong_ordering operator&lt;=&gt;(<i>unspecified</i>, strong_ordering v) noexcept;
  };

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

<p>Remove just the extra <code class="language-cpp">==</code> and <code class="language-cpp">!=</code> operators from 17.11.2.6 [cmp.strongord]/6 and /7:</p>
<blockquote>
<p><pre><code>constexpr bool operator==(strong_ordering v, <i>unspecified</i>) noexcept;
<del>constexpr bool operator!=(strong_ordering v, <i>unspecified</i>) noexcept;</del>
constexpr bool operator&lt; (strong_ordering v, <i>unspecified</i>) noexcept;
constexpr bool operator&gt; (strong_ordering v, <i>unspecified</i>) noexcept;
constexpr bool operator&lt;=(strong_ordering v, <i>unspecified</i>) noexcept;
constexpr bool operator&gt;=(strong_ordering v, <i>unspecified</i>) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">v.value @ 0</code> for <code class="language-cpp">operator@</code>.
<pre><code><del>constexpr bool operator==(<i>unspecified</i>, strong_ordering v) noexcept;</del>
<del>constexpr bool operator!=(<i>unspecified</i>, strong_ordering v) noexcept;</del>
constexpr bool operator&lt; (<i>unspecified</i>, strong_ordering v) noexcept;
constexpr bool operator&gt; (<i>unspecified</i>, strong_ordering v) noexcept;
constexpr bool operator&lt;=(<i>unspecified</i>, strong_ordering v) noexcept;
constexpr bool operator&gt;=(<i>unspecified</i>, strong_ordering v) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">0 @ v.value</code> for <code class="language-cpp">operator@</code>.</p>
</blockquote>
<p>Add a new subclause [cmp.concept] "concept <code class="language-cpp">ThreeWayComparable</code>":</p>
<blockquote>
<p><pre><code class="language-cpp">template &lt;typename T, typename Cat&gt;
  concept </code><code><i>compares-as</i></code><code class="language-cpp"> = // exposition only
    Same&lt;common_comparison_category_t&lt;T, Cat&gt;, Cat&gt;;</code></pre></p>
<p><pre><code class="language-cpp">template&lt;class T, class U&gt;
  concept </code><code><i>partially-ordered-with</i></code><code class="language-cpp"> = // exposition only
    requires(const remove_reference_t&lt;T&gt;&amp; t,
             const remove_reference_t&lt;U&gt;&amp; u) {
      { t &lt; u } -&gt; Boolean;
      { t &gt; u } -&gt; Boolean;
      { t &lt;= u } -&gt; Boolean;
      { t &gt;= u } -&gt; Boolean;
      { u &lt; t } -&gt; Boolean;
      { u &gt; t } -&gt; Boolean;
      { u &lt;= t } -&gt; Boolean;
      { u &gt;= t } -&gt; Boolean;    <br />
    };</code></pre></p>
<p>Let <code class="language-cpp">t</code> and <code class="language-cpp">u</code> be lvalues of types <code class="language-cpp">const remove_reference_t&lt;T&gt;</code> and <code class="language-cpp">const remove_reference_t&lt;U&gt;</code> respectively. <code><i>partially-ordered-with</i>&lt;T, U&gt;</code> is satisfied only if:</p>
<ul>
<li><code class="language-cpp">t &lt; u</code>, <code class="language-cpp">t &lt;= u</code>, <code class="language-cpp">t &gt; u</code>, <code class="language-cpp">t &gt;= u</code>, <code class="language-cpp">u &lt; t</code>, <code class="language-cpp">u &lt;= t</code>, <code class="language-cpp">u &gt; t</code>, and <code class="language-cpp">u &gt;= t</code> have the same domain.</li>
<li><code class="language-cpp">bool(t &lt; u) == bool(u &gt; t)</code></li>
<li><code class="language-cpp">bool(u &lt; t) == bool(t &gt; u)</code></li>
<li><code class="language-cpp">bool(t &lt;= u) == bool(u &gt;= t)</code></li>
<li><code class="language-cpp">bool(u &lt;= t) == bool(t &gt;= u)</code></li>
</ul>
<p><pre><code class="language-cpp">template &lt;typename T, typename Cat = partial_ordering&gt;
  concept ThreeWayComparable =
    </code><code><i>weakly-equality-comparable-with</i></code><code class="language-cpp">&lt;T, T&gt; &amp;&amp;
    (!ConvertibleTo&lt;Cat, partial_ordering&gt; || </code><code><i>partially-ordered-with</i></code><code class="language-cpp">&lt;T, T&gt;) &amp;&amp;
    requires(const remove_reference_t&lt;T&gt;&amp; a,
             const remove_reference_t&lt;T&gt;&amp; b) {
      { a &lt;=&gt; b } -&gt; </code><code><i>compares-as</i></code><code class="language-cpp">&lt;Cat&gt;;
    };</code></pre></p>
<p>Let <code class="language-cpp">a</code> and <code class="language-cpp">b</code> be lvalues of type <code class="language-cpp">const remove_reference_t&lt;T&gt;</code>. <code class="language-cpp">T</code> and <code class="language-cpp">Cat</code> model <code class="language-cpp">ThreeWayComparable&lt;T, Cat&gt;</code> only if:</p>
<ul>
<li><code class="language-cpp">(a &lt;=&gt; b == 0) == bool(a == b)</code>.</li>
<li><code class="language-cpp">(a &lt;=&gt; b != 0) == bool(a != b)</code>.</li>
<li><code class="language-cpp">((a &lt;=&gt; b) &lt;=&gt; 0)</code> and <code class="language-cpp">(0 &lt;=&gt; (b &lt;=&gt; a))</code> are equal</li>
<li>If <code class="language-cpp">Cat</code> is convertible to <code class="language-cpp">strong_equality</code>, <code class="language-cpp">T</code> models <code class="language-cpp">EqualityComparable</code> ([concept.equalitycomparable]).</li>
<li>If <code class="language-cpp">Cat</code> is convertible to <code class="language-cpp">partial_ordering</code>:<ul>
<li><code class="language-cpp">(a &lt;=&gt; b &lt; 0) == bool(a &lt; b)</code>.</li>
<li><code class="language-cpp">(a &lt;=&gt; b &gt; 0) == bool(a &gt; b)</code>.</li>
<li><code class="language-cpp">(a &lt;=&gt; b &lt;= 0) == bool(a &lt;= b)</code>.</li>
<li><code class="language-cpp">(a &lt;=&gt; b &gt;= 0) == bool(a &gt;= b)</code>.</li>
</ul>
</li>
<li>If <code class="language-cpp">Cat</code> is convertible to <code class="language-cpp">strong_ordering</code>, <code class="language-cpp">T</code> models <code class="language-cpp">StrictTotallyOrdered</code> ([concept.stricttotallyordered]). </li>
</ul>
<p><pre><code class="language-cpp">template &lt;typename T, typename U,
          typename Cat = partial_ordering&gt;
  concept ThreeWayComparableWith = 
    </code><code><i>weakly-equality-comparable-with</i></code><code class="language-cpp">&lt;T, U&gt; &amp;&amp;
    (!ConvertibleTo&lt;Cat, partial_ordering&gt; || </code><code><i>partially-ordered-with</i></code><code class="language-cpp">&lt;T, U&gt;) &amp;&amp;
    ThreeWayComparable&lt;T, Cat&gt; &amp;&amp;
    ThreeWayComparable&lt;U, Cat&gt; &amp;&amp;
    CommonReference&lt;const remove_reference_t&lt;T&gt;&amp;, const remove_reference_t&lt;U&gt;&amp;&gt; &amp;&amp;
    ThreeWayComparable&lt;
      common_reference_t&lt;const remove_reference_t&lt;T&gt;&amp;, const remove_reference_t&lt;U&gt;&amp;&gt;,
      Cat&gt; &amp;&amp;
    requires(const remove_reference_t&lt;T&gt;&amp; t,
             const remove_reference_t&lt;U&gt;&amp; u) {
      { t &lt;=&gt; u } -&gt; </code><code><i>compares-as</i></code><code class="language-cpp">&lt;Cat&gt;;
      { u &lt;=&gt; t } -&gt; </code><code><i>compares-as</i></code><code class="language-cpp">&lt;Cat&gt;;
    };</code></pre>
Let <code class="language-cpp">t</code> and <code class="language-cpp">u</code> be lvalues of types <code class="language-cpp">const remove_reference_t&lt;T&gt;</code> and <code class="language-cpp">const remove_reference_t&lt;U&gt;</code>, respectively. Let <code class="language-cpp">C</code> be <code class="language-cpp">common_reference_t&lt;const remove_reference_t&lt;T&gt;&amp;, const remove_reference_t&lt;U&gt;&amp;&gt;</code>. <code class="language-cpp">T</code>, <code class="language-cpp">U</code>, and <code class="language-cpp">Cat</code> model <code class="language-cpp">ThreeWayComparableWith&lt;T, U, Cat&gt;</code> only if:</p>
<ul>
<li><code class="language-cpp">t &lt;=&gt; u</code> and <code class="language-cpp">u &lt;=&gt; t</code> have the same domain.</li>
<li><code class="language-cpp">((t &lt;=&gt; u) &lt;=&gt; 0)</code> and <code class="language-cpp">(0 &lt;=&gt; (u &lt;=&gt; t))</code> are equal</li>
<li><code class="language-cpp">(t &lt;=&gt; u == 0) == bool(t == u)</code>.</li>
<li><code class="language-cpp">(t &lt;=&gt; u != 0) == bool(t != u)</code>.</li>
<li><code class="language-cpp">Cat(t &lt;=&gt; u) == Cat(C(t) &lt;=&gt; C(u))</code>.</li>
<li>If <code class="language-cpp">Cat</code> is convertible to <code class="language-cpp">strong_equality</code>, <code class="language-cpp">T</code> and <code class="language-cpp">U</code> model <code class="language-cpp">EqualityComparableWith&lt;T, U&gt;</code> ([concepts.equalitycomparable]).</li>
<li>If <code class="language-cpp">Cat</code> is convertible to <code class="language-cpp">partial_ordering</code>:<ul>
<li><code class="language-cpp">(t &lt;=&gt; u &lt; 0) == bool(t &lt; u)</code></li>
<li><code class="language-cpp">(t &lt;=&gt; u &gt; 0) == bool(t &gt; u)</code></li>
<li><code class="language-cpp">(t &lt;=&gt; u &lt;= 0) == bool(t &lt;= u)</code></li>
<li><code class="language-cpp">(t &lt;=&gt; u &gt;= 0) == bool(t &gt;= u)</code></li>
</ul>
</li>
<li>If <code class="language-cpp">Cat</code> is convertible to <code class="language-cpp">strong_ordering</code>, <code class="language-cpp">T</code> and <code class="language-cpp">U</code> model <code class="language-cpp">StrictTotallyOrderedWith&lt;T, U&gt;</code> ([concepts.stricttotallyordered]).</li>
</ul>
</blockquote>
<p>Add a new subclause [cmp.result] "spaceship invocation result":</p>
<blockquote>
<p>The behavior of a program that adds specializations for the <code class="language-cpp">compare_three_way_result</code> template defined in this subclause is undefined.</p>
<p>For the <code class="language-cpp">compare_three_way_result</code> type trait applied to the types <code class="language-cpp">T</code> and <code class="language-cpp">U</code>, let <code class="language-cpp">t</code> and <code class="language-cpp">u</code> denote lvalues of types <code class="language-cpp">const remove_reference_t&lt;T&gt;</code> and <code class="language-cpp">const remove_reference_t&lt;U&gt;</code>, respectively. If the expression <code class="language-cpp">t &lt;=&gt; u</code> is well-formed, the member <em>typedef-name</em> <code class="language-cpp">type</code> denotes the type <code class="language-cpp">decltype(t &lt;=&gt; u)</code>. Otherwise, there is no member <code class="language-cpp">type</code>.</p>
</blockquote>
<p>Add a new subclause [cmp.object] "spaceship object":</p>
<blockquote>
<p>In this subclause, <code class="language-cpp">BUILTIN_PTR_3WAY(T, U)</code> for types <code class="language-cpp">T</code> and <code class="language-cpp">U</code> is a boolean constant expression. <code class="language-cpp">BUILTIN_PTR_3WAY(T, U)</code> is <code class="language-cpp">true</code> if and only if <code class="language-cpp">&lt;=&gt;</code> in the expression <code class="language-cpp">declval&lt;T&gt;() &lt;=&gt; declval&lt;U&gt;()</code> resolves to a built-in operator comparing pointers.</p>
<pre class="codehilite"><code class="language-cpp">struct compare_three_way {
  template&lt;class T, class U&gt;
    requires ThreeWayComparableWith&lt;T,U&gt; || BUILTIN_PTR_3WAY(T, U)
  constexpr auto operator()(T&amp;&amp; t, U&amp;&amp; u) const;

  using is_transparent = unspecified;
};</code></pre>


<p><em>Expects</em>: If the expression <code class="language-cpp">std::forward&lt;T&gt;(t) &lt;=&gt; std::forward&lt;U&gt;(u)</code> results in a call to a built-in operator <code class="language-cpp">&lt;=&gt;</code> comparing pointers of type <code class="language-cpp">P</code>, the conversion sequences from both <code class="language-cpp">T</code> and <code class="language-cpp">U</code> to <code class="language-cpp">P</code> are equality-preserving ([concepts.equality]).</p>
<p><em>Effects</em>: </p>
<ul>
<li>If the expression <code class="language-cpp">std::forward&lt;T&gt;(t) &lt;=&gt; std::forward&lt;U&gt;(u)</code> results in a call to a built-in operator <code class="language-cpp">&lt;=&gt;</code> comparing pointers of type <code class="language-cpp">P</code>: returns <code class="language-cpp">strong_ordering::less</code> if (the converted value of) <code class="language-cpp">t</code> precedes <code class="language-cpp">u</code> in the implementation-defined strict total order ([range.cmp]) over pointers of type <code class="language-cpp">P</code>, <code class="language-cpp">strong_ordering::greater</code> if <code class="language-cpp">u</code> precedes <code class="language-cpp">t</code>, and otherwise <code class="language-cpp">strong_ordering::equal</code>.</li>
<li>Otherwise, equivalent to: <code class="language-cpp">return std::forward&lt;T&gt;(t) &lt;=&gt; std::forward&lt;U&gt;(u);</code></li>
</ul>
<p>In addition to being available via inclusion of the <code class="language-cpp">&lt;compare&gt;</code> header, the class <code class="language-cpp">compare_three_way</code> is available when the header <code class="language-cpp">&lt;functional&gt;</code> is included.</p>
</blockquote>
<p>Replace the entirety of 17.11.4 [cmp.alg]. This wording relies on the specification-only function <code class="language-cpp">3WAY&lt;R&gt;</code> defined in <a href="https://wg21.link/p1186r1" title="When do you actually use &lt;=&gt;?">P1186R1</a>.</p>
<blockquote>
<p><pre><code><del>template&lt;class T&gt; constexpr strong_ordering strong_order(const T&amp; a, const T&amp; b);</del></code></pre>
<del><em>Effects</em>: Compares two values and produces a result of type <code class="language-cpp">strong_ordering</code>:</del>  </p>
<ul>
<li><del>If numeric_limits<T>::is_iec559 is true, returns a result of type strong_ordering that is consistent with the totalOrder operation as specified in ISO/IEC/IEEE 60559.</del></li>
<li><del>Otherwise, returns a &lt;=&gt; b if that expression is well-formed and convertible to strong_ordering.</del></li>
<li><del>Otherwise, if the expression a &lt;=&gt; b is well-formed, then the function is defined as deleted.</del></li>
<li><del>Otherwise, if the expressions a == b and a &lt; b are each well-formed and convertible to bool, then</del><ul>
<li><del>if a == b is true, returns strong_ordering::equal;</del></li>
<li><del>otherwise, if a &lt; b is true, returns strong_ordering::less;</del></li>
<li><del>otherwise, returns strong_ordering::greater.</del></li>
</ul>
</li>
<li><del>Otherwise, the function is defined as deleted.</del></li>
</ul>
<p><pre><code><del>template&lt;class T&gt; constexpr weak_ordering weak_order(const T&amp; a, const T&amp; b);</del></code></pre>
<del><em>Effects</em>: Compares two values and produces a result of type weak_ordering:</del></p>
<ul>
<li><del>Returns a &lt;=&gt; b if that expression is well-formed and convertible to weak_ordering.</del></li>
<li><del>Otherwise, if the expression a &lt;=&gt; b is well-formed, then the function is defined as deleted.</del></li>
<li><del>Otherwise, if the expressions a == b and a &lt; b are each well-formed and convertible to bool, then</del><ul>
<li><del>if a == b is true, returns weak_ordering::equivalent;</del></li>
<li><del>otherwise, if a &lt; b is true, returns weak_ordering::less;</del></li>
<li><del>otherwise, returns weak_ordering::greater.</del></li>
</ul>
</li>
<li><del>Otherwise, the function is defined as deleted.</del></li>
</ul>
<p><pre><code><del>template&lt;class T&gt; constexpr partial_ordering partial_order(const T&amp; a, const T&amp; b);</del></code></pre>
<del><em>Effects</em>: Compares two values and produces a result of type partial_ordering:</del></p>
<ul>
<li><del>Returns a &lt;=&gt; b if that expression is well-formed and convertible to partial_ordering.</del></li>
<li><del>Otherwise, if the expression a &lt;=&gt; b is well-formed, then the function is defined as deleted.</del></li>
<li><del>Otherwise, if the expressions a == b and a &lt; b are each well-formed and convertible to bool, then</del><ul>
<li><del>if a == b is true, returns partial_ordering::equivalent;</del></li>
<li><del>otherwise, if a &lt; b is true, returns partial_ordering::less;</del></li>
<li><del>otherwise, returns partial_ordering::greater.</del></li>
</ul>
</li>
<li><del>Otherwise, the function is defined as deleted.</del></li>
</ul>
<p><pre><code><del>template&lt;class T&gt; constexpr strong_equality strong_equal(const T&amp; a, const T&amp; b);</del></code></pre>
<del><em>Effects</em>: Compares two values and produces a result of type strong_equality:</del></p>
<ul>
<li><del>Returns a &lt;=&gt; b if that expression is well-formed and convertible to strong_equality.</del></li>
<li><del>Otherwise, if the expression a &lt;=&gt; b is well-formed, then the function is defined as deleted.</del></li>
<li><del>Otherwise, if the expression a == b is well-formed and convertible to bool, then</del><ul>
<li><del>if a == b is true, returns strong_equality::equal;</del></li>
<li><del>otherwise, returns strong_equality::nonequal.</del></li>
</ul>
</li>
<li><del>Otherwise, the function is defined as deleted.</del></li>
</ul>
<p><pre><code><del>template&lt;class T&gt; constexpr weak_equality weak_equal(const T&amp; a, const T&amp; b);</del></code></pre>
<del><em>Effects</em>: Compares two values and produces a result of type weak_equality:</del></p>
<ul>
<li><del>Returns a &lt;=&gt; b if that expression is well-formed and convertible to weak_equality.</del></li>
<li><del>Otherwise, if the expression a &lt;=&gt; b is well-formed, then the function is defined as deleted.</del></li>
<li><del>Otherwise, if the expression a == b is well-formed and convertible to bool, then</del><ul>
<li><del>if a == b is true, returns weak_equality::equivalent;</del></li>
<li><del>otherwise, returns weak_equality::nonequivalent.</del></li>
</ul>
</li>
<li><del>Otherwise, the function is defined as deleted.</del></li>
</ul>
<p><ins>The name <code class="language-cpp">strong_order</code> denotes a customization point object ([customization.point.object]). The expression <code class="language-cpp">strong_order(E, F)</code> for some subexpressions <code class="language-cpp">E</code> and <code class="language-cpp">F</code> is expression-equivalent ([defns.expression-equivalent]) to the following:</p>
<ul>
<li><ins>If the decayed types of <code class="language-cpp">E</code> and <code class="language-cpp">F</code> differ, <code class="language-cpp">strong_order(E, F)</code> is ill-formed.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">strong_ordering(strong_order(E, F))</code> if it is a well-formed expression with overload resolution performed in a context that does not include a declaration of <code class="language-cpp">std::strong_order</code>.</ins></li>
<li><ins>Otherwise, if the decayed type <code class="language-cpp">T</code> of <code class="language-cpp">E</code> and <code class="language-cpp">F</code> is a floating point type, yields a value of type <code class="language-cpp">strong_ordering</code> that is consistent with the ordering observed by <code class="language-cpp">T</code>'s comparison operators, and if <code class="language-cpp">numeric_limits&lt;T&gt;::is_iec559</code> is <code class="language-cpp">true</code> is additionally consistent with the totalOrder operation as specified in ISO/IEC/IEEE 60599.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">strong_ordering(E &lt;=&gt; F)</code> if it is a well-formed expression.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">strong_order(E, F)</code> is ill-formed. [<em>Note</em>: This case can result in substitution failure when <code class="language-cpp">strong_order(E, F)</code> appears in the immediate context of a template instantiation. —<em>end note</em>]</ins></li>
</ul>
<p><ins>The name <code class="language-cpp">weak_order</code> denotes a customization point object ([customization.point.object]). The expression <code class="language-cpp">weak_order(E, F)</code> for some subexpressions <code class="language-cpp">E</code> and <code class="language-cpp">F</code> is expression-equivalent ([defns.expression-equivalent]) to the following:</ins></p>
<ul>
<li><ins>If the decayed types of <code class="language-cpp">E</code> and <code class="language-cpp">F</code> differ, <code class="language-cpp">weak_order(E, F)</code> is ill-formed.</ins> </li>
<li><ins>Otherwise, <code class="language-cpp">weak_ordering(weak_order(E, F))</code> if it is a well-formed expression with overload resolution performed in a context that does not include a declaration of <code class="language-cpp">std::weak_order</code>.</ins></li>
<li><ins>Otherwise, if the decayed type <code class="language-cpp">T</code> of <code class="language-cpp">E</code> and <code class="language-cpp">F</code> is a floating point type, yields a value of type <code class="language-cpp">weak_ordering</code> that is consistent with the ordering observed by <code class="language-cpp">T</code>'s comparison operators and <code class="language-cpp">strong_order</code>, and if <code class="language-cpp">numeric_liits&lt;T&gt;::is_iec559</code> is <code class="language-cpp">true</code> is additionally consistent with the following equivalence classes, ordered from lesser to greater:</ins><ul>
<li><ins>Together, all negative NaN values</ins></li>
<li><ins>Negative infinity</ins></li>
<li><ins>Each normal negative value</ins></li>
<li><ins>Each subnormal negative value</ins></li>
<li><ins>Together, both zero values</ins></li>
<li><ins>Each subnormal positive value</ins></li>
<li><ins>Each normal positive value</ins></li>
<li><ins>Positive infinity</ins></li>
<li><ins>Together, all positive NaN values</ins></li>
</ul>
</li>
<li><ins>Otherwise, <code class="language-cpp">weak_ordering(strong_order(E, F))</code> if it is a well-formed expression.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">weak_ordering(E &lt;=&gt; F)</code> if it is a well-formed expression.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">weak_order(E, F)</code> is ill-formed. [<em>Note</em>: This case can result in substitution failure when <code class="language-cpp">std::weak_order(E, F)</code> appears in the immediate context of a template instantiation. —<em>end note</em>]</ins></li>
</ul>
<p><ins>The name <code class="language-cpp">partial_order</code> denotes a customization point object ([customization.point.object]). The expression <code class="language-cpp">partial_order(E, F)</code> for some subexpressions <code class="language-cpp">E</code> and <code class="language-cpp">F</code> is expression-equivalent ([defns.expression-equivalent]) to the following:</ins></p>
<ul>
<li><ins>If the decayed types of <code class="language-cpp">E</code> and <code class="language-cpp">F</code> differ, <code class="language-cpp">partial_order(E, F)</code> is ill-formed.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">partial_ordering(partial_order(E, F))</code> if it is a well-formed expression with overload resolution performed in a context that does not include a declaration of <code class="language-cpp">std::partial_order</code>.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">partial_ordering(weak_order(E, F))</code> if it is a well-formed expression.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">partial_ordering(E &lt;=&gt; F)</code> if it is a well-formed expression.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">partial_order(E, F)</code> is ill-formed. [<em>Note</em>: This case can result in substitution failure when <code class="language-cpp">std::partial_order(E, F)</code> appears in the immediate context of a template instantiation. —<em>end note</em>]</ins>
</li>
</ul>
<p><ins>The name <code class="language-cpp">compare_strong_order_fallback</code> denotes a comparison customization point ([customization.point.object]) object. The expression <code class="language-cpp">compare_strong_order_fallback(E, F)</code> for some subexpressions <code class="language-cpp">E</code> and <code class="language-cpp">F</code> is expression-equivalent ([defns.expression-equivalent]) to:</ins></p>
<ul>
<li><ins>If the decayed types of <code class="language-cpp">E</code> and <code class="language-cpp">F</code> differ, <code class="language-cpp">compare_strong_order_fallback(E, F)</code> is ill-formed.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">strong_order(E, F)</code> if it is a well-formed expression.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">3WAY&lt;strong_ordering&gt;(E, F)</code> ([class.spaceship]) if it is a well-formed expression.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">compare_strong_order_fallback(E, F)</code> is ill-formed.</ins></li>
</ul>
<p><ins>The name <code class="language-cpp">compare_weak_order_fallback</code> denotes a customization point object ([customization.point.object]). The expression <code class="language-cpp">compare_weak_order_fallback(E, F)</code> for some subexpressions <code class="language-cpp">E</code> and <code class="language-cpp">F</code> is expression-equivalent ([defns.expression-equivalent]) to:</ins></p>
<ul>
<li><ins>If the decayed types of <code class="language-cpp">E</code> and <code class="language-cpp">F</code> differ, <code class="language-cpp">compare_weak_order_fallback(E, F)</code> is ill-formed.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">weak_order(E, F)</code> if it is a well-formed expression.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">3WAY&lt;weak_ordering&gt;(E, F)</code> ([class.spaceship]) if it is a well-formed expression.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">compare_weak_order_fallback(E, F)</code> is ill-formed.</ins></li>
</ul>
<p><ins>The name <code class="language-cpp">compare_partial_order_fallback</code> denotes a customization point object ([customization.point.object]). The expression <code class="language-cpp">compare_partial_order_fallback(E, F)</code> for some subexpressions <code class="language-cpp">E</code> and <code class="language-cpp">F</code> is expression-equivalent ([defns.expression-equivalent]) to:</ins></p>
<ul>
<li><ins>If the decayed types of <code class="language-cpp">E</code> and <code class="language-cpp">F</code> differ, <code class="language-cpp">compare_partial_order_fallback(E, F)</code> is ill-formed.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">partial_order(E, F)</code> if it is a well-formed expression.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">3WAY&lt;partial_ordering&gt;(E, F)</code> ([class.spaceship]) if it is a well-formed expression.</ins></li>
<li><ins>Otherwise, <code class="language-cpp">compare_partial_order_fallback(E, F)</code> is ill-formed.</ins></li>
</ul>
</blockquote>
<p>Change 17.13.1 [coroutine.syn]:</p>
<blockquote><pre><code>namespace std {
  [...]
  // 17.13.5 noop coroutine
  noop_coroutine_handle noop_coroutine() noexcept;

<del>  // 17.13.3.6 comparison operators:
  constexpr bool operator==(coroutine_handle&lt;&gt; x, coroutine_handle&lt;&gt; y) noexcept;
  constexpr bool operator!=(coroutine_handle&lt;&gt; x, coroutine_handle&lt;&gt; y) noexcept;
  constexpr bool operator&lt;(coroutine_handle&lt;&gt; x, coroutine_handle&lt;&gt; y) noexcept;
  constexpr bool operator&gt;(coroutine_handle&lt;&gt; x, coroutine_handle&lt;&gt; y) noexcept;
  constexpr bool operator&lt;=(coroutine_handle&lt;&gt; x, coroutine_handle&lt;&gt; y) noexcept;
  constexpr bool operator&gt;=(coroutine_handle&lt;&gt; x, coroutine_handle&lt;&gt; y) noexcept;</del>

  // 17.13.6 trivial awaitables
  [...]
}</code></pre></blockquote>

<p>Change 17.13.3 [coroutine.handle]:</p>
<blockquote><pre><code>namespace std {
  template &lt;&gt;
  struct coroutine_handle&lt;void&gt;
  {
    [...]
    // 17.13.3.4 resumption
    void operator()() const;
    void resume() const;
    void destroy() const;

<ins>    // comparison operators
    friend constexpr bool operator==(coroutine_handle x, coroutine_handle y) noexcept
    { return x.address() == y.address(); }
    friend constexpr strong_ordering operator&lt;=&gt;(coroutine_handle x, coroutine_handle y) noexcept
    { return compare_three_way()(x.address(), y.address()); }</ins>
  private:
    void* ptr; // exposition only
  };
  [...]
}</code></pre></blockquote>

<p>Remove 17.13.3.6 [coroutine.handle.compare] (as it's now all defined in the header):</p>
<blockquote>
<p><pre><code><del>constexpr bool operator==(coroutine_handle&lt;&gt; x, coroutine_handle&lt;&gt; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">x.address() == y.address()</code>.</del>
<pre><code><del>constexpr bool operator!=(coroutine_handle&lt;&gt; x, coroutine_handle&lt;&gt; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(x == y)</code>.</del>
<pre><code>&lt;<del>constexpr bool operator&lt;(coroutine_handle&lt;&gt; x, coroutine_handle&lt;&gt; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">less&lt;&gt;()(x.address(), y.address())</code>.</del>
<pre><code><del>constexpr bool operator&gt;(coroutine_handle&lt;&gt; x, coroutine_handle&lt;&gt; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">(y &lt; x)</code>.</del>
<pre><code><del>constexpr bool operator&lt;=(coroutine_handle&lt;&gt; x, coroutine_handle&lt;&gt; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(x &gt; y)</code>.</del>
<pre><code><del>constexpr bool operator&gt;=(coroutine_handle&lt;&gt; x, coroutine_handle&lt;&gt; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(x &lt; y)</code>.</del></p>
</blockquote>
<h3 id="clause-18-concepts-library">4.3. Clause 18: Concepts Library<a class="self-link" href="#clause-18-concepts-library"></a></h3>
<p>No changes.</p>
<h3 id="clause-19-diagnostics-library">4.4. Clause 19: Diagnostics Library<a class="self-link" href="#clause-19-diagnostics-library"></a></h3>
<p>Changed operators for: <code class="language-cpp">error_category</code>, <code class="language-cpp">error_code</code>, and <code class="language-cpp">error_condition</code></p>
<p>Change 19.5.1 [system_error.syn]</p>
<blockquote><pre><code>namespace std {
  [...]
  // [syserr.errcondition.nonmembers], non-member functions
  error_condition make_error_condition(errc e) noexcept;

<del>  // [syserr.compare], comparison functions
  bool operator==(const error_code& lhs, const error_code& rhs) noexcept;
  bool operator==(const error_code& lhs, const error_condition& rhs) noexcept;
  bool operator==(const error_condition& lhs, const error_code& rhs) noexcept;
  bool operator==(const error_condition& lhs, const error_condition& rhs) noexcept;
  bool operator!=(const error_code& lhs, const error_code& rhs) noexcept;
  bool operator!=(const error_code& lhs, const error_condition& rhs) noexcept;
  bool operator!=(const error_condition& lhs, const error_code& rhs) noexcept;
  bool operator!=(const error_condition& lhs, const error_condition& rhs) noexcept;
  bool operator&lt; (const error_code& lhs, const error_code& rhs) noexcept;
  bool operator&lt; (const error_condition& lhs, const error_condition& rhs) noexcept;</del>

  // [syserr.hash], hash support
  [...]
}</code></pre></blockquote>

<p>Change 19.5.2.1 [syserr.errcat.overview]:</p>
<blockquote><pre><code>namespace std {
  class error_category {
    [...]
    bool operator==(const error_category& rhs) const noexcept;
    <del>bool operator!=(const error_category& rhs) const noexcept;</del>
    <del>bool operator< (const error_category& rhs) const noexcept;</del>
    <ins>strong_ordering operator<=>(const error_category& rhs) const noexcept;</ins>
  };
  [...]
}</code></pre></blockquote>

<p>Change 19.5.2.3 [syserr.errcat.nonvirtuals]:</p>
<blockquote>
<p><pre><code>bool operator==(const error_category&amp; rhs) const noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">this == &amp;rhs</code>.
<pre><code><del>bool operator!=(const error_category&amp; rhs) const noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(*this == rhs)</code>.</del>
<pre><code><del>bool operator&lt;(const error_category&amp; rhs) const noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">less&lt;const error_category*&gt;()(this, &amp;rhs)</code>.</del><br />
<del>[Note: <code class="language-cpp">less</code> (19.14.7) provides a total ordering for pointers. —end note]</del>
<pre><code><ins>strong_ordering operator&lt;=&gt;(const error_category&amp; rhs) const noexcept;</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">compare_three_way()(this, &amp;rhs)</code>.</ins><br />
<ins>[Note: <code class="language-cpp">compare_three_way</code> (cmp.object) provides a total ordering for pointers. —end note]</ins></p>
</blockquote>
<p>Change 19.5.3.1 [syserr.errcode.overview]:</p>
<blockquote><pre><code>namespace std {
  class error_code {
    [...]
    <ins>// [syserr.compare], comparison functions</ins>
    <ins>friend bool operator==(const error_code&, const error_code&) { <i>see below</i>; }</ins>
    <ins>friend strong_ordering operator&lt;=&gt;(const error_code&, const error_code&) { <i>see below</i>; }</ins>
    <ins>friend bool operator==(const error_code&, const error_condition&) { <i>see below</i>; }</ins>
  private:
    int val_;                   // exposition only
    const error_category* cat_; // exposition only
  };

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

<p>Change 19.5.4.1 [syserr.errcondition.overview]:</p>
<blockquote><pre><code>namespace std {
  class error_condition {
  public:
    [...]
    <ins>// [syserr.compare], comparison functions</ins>
    <ins>friend bool operator==(const error_condition&, const error_condition&) { <i>see below</i>; }</ins>
    <ins>friend strong_ordering operator&lt;=&gt;(const error_condition&, const error_condition&) { <i>see below</i>; }</ins>
    <ins>friend bool operator==(const error_condition&, const error_code&) { <i>see below</i>; }</ins>
  private:
    int val_;                   // exposition only
    const error_category* cat_; // exposition only
  };
}</code></pre></blockquote>

<p>Change 19.5.5 [syserr.compare]</p>
<blockquote>
<p><pre><code><ins>friend </ins>bool operator==(const error_code&amp; lhs, const error_code&amp; rhs) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">lhs.category() == rhs.category() &amp;&amp; lhs.value() == rhs.value()</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><ins>friend </ins>bool operator==(const error_code&amp; lhs, const error_condition&amp; rhs) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">lhs.category().equivalent(lhs.value(), rhs) || rhs.category().equivalent(lhs, rhs.value())</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><ins>friend </ins>bool operator==(const error_condition&amp; lhs, const error_code&amp; rhs) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">rhs.category().equivalent(rhs.value(), lhs) || lhs.category().equivalent(rhs, lhs.value())</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><ins>friend </ins>bool operator==(const error_condition&amp; lhs, const error_condition&amp; rhs) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">lhs.category() == rhs.category() &amp;&amp; lhs.value() == rhs.value()</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><del>bool operator!=(const error_code&amp; lhs, const error_code&amp; rhs) noexcept;</del>
<del>bool operator!=(const error_code&amp; lhs, const error_condition&amp; rhs) noexcept;</del>
<del>bool operator!=(const error_condition&amp; lhs, const error_code&amp; rhs) noexcept;</del>
<del>bool operator!=(const error_condition&amp; lhs, const error_condition&amp; rhs) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(lhs == rhs)</code>.</del>
<code><pre><del>bool operator&lt;(const error_code&amp; lhs, const error_code&amp; rhs) noexcept;</del></code></pre>
<del><em>Returns</em>:
<code class="language-cpp">lhs.category() &lt; rhs.category() ||
(lhs.category() == rhs.category() &amp;&amp; lhs.value() &lt; rhs.value())</code></del>
<code><pre><del>bool operator&lt;(const error_condition&amp; lhs, const error_condition&amp; rhs) noexcept;</del></code></pre>
<del><em>Returns</em>:
<code class="language-cpp">lhs.category() &lt; rhs.category() ||
(lhs.category() == rhs.category() &amp;&amp; lhs.value() &lt; rhs.value())</code></del>
<pre><code><ins>friend strong_ordering operator&lt;=&gt;(const error_code&amp; lhs, const error_code&amp; rhs) noexcept;</ins></code></pre>
<ins><em>Effects</em>: Equivalent to:</ins>
<blockquote class="ins"><pre><code>if (auto c = lhs.category() &lt;=&gt; rhs.category(); c != 0) return c;
return lhs.value() &lt;=&gt; rhs.value();</code></pre></blockquote><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><ins>friend strong_ordering operator&lt;=&gt;(const error_condition&amp; lhs, const error_condition&amp; rhs) noexcept;</ins></code></pre>
<ins><em>Effects</em>: Equivalent to:</ins>
<blockquote class="ins"><pre><code>if (auto c = lhs.category() &lt;=&gt; rhs.category(); c != 0) return c;
return lhs.value() &lt;=&gt; rhs.value();</code></pre></blockquote><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins></p>
</blockquote>
<h3 id="clause-20-general-utilities-library">4.5. Clause 20: General utilities library<a class="self-link" href="#clause-20-general-utilities-library"></a></h3>
<p>Changed operators for: <code class="language-cpp">pair</code>, <code class="language-cpp">tuple</code>, <code class="language-cpp">optional</code>, <code class="language-cpp">variant</code>, <code class="language-cpp">monostate</code>, <code class="language-cpp">bitset</code>, <code class="language-cpp">allocator</code>, <code class="language-cpp">unique_ptr</code>, <code class="language-cpp">shared_ptr</code>, <code class="language-cpp">memory_resource</code>, <code class="language-cpp">polymorphic_allocator</code>, <code class="language-cpp">scoped_allocator_adaptor</code>, <code class="language-cpp">function</code>, <code class="language-cpp">type_index</code></p>
<p>Change 20.2.1 [utility.syn]</p>
<blockquote><pre><code>#include <initializer_list> // see 16.10.1

namespace std {
  [...]
  // 20.4, class template pair
  template&lt;class T1, class T2&gt;
  struct pair;

  <del>// 20.4.3, pair specialized algorithms</del>
  <del>template&lt;class T1, class T2&gt;</del>
  <del>constexpr bool operator==(const pair&lt;T1, T2&gt;&, const pair&lt;T1, T2&gt;&);</del>
  <del>template&lt;class T1, class T2&gt;</del>
  <del>constexpr bool operator!=(const pair&lt;T1, T2&gt;&, const pair&lt;T1, T2&gt;&);</del>
  <del>template&lt;class T1, class T2&gt;</del>
  <del>constexpr bool operator&lt; (const pair&lt;T1, T2&gt;&, const pair&lt;T1, T2&gt;&);</del>
  <del>template&lt;class T1, class T2&gt;</del>
  <del>constexpr bool operator&gt; (const pair&lt;T1, T2&gt;&, const pair&lt;T1, T2&gt;&);</del>
  <del>template&lt;class T1, class T2&gt;</del>
  <del>constexpr bool operator&lt;=(const pair&lt;T1, T2&gt;&, const pair&lt;T1, T2&gt;&);</del>
  <del>template&lt;class T1, class T2&gt;</del>
  <del>constexpr bool operator&gt;=(const pair&lt;T1, T2&gt;&, const pair&lt;T1, T2&gt;&);</del>

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

<p>Change 20.4.2 [pairs.pair]:</p>
<blockquote><pre><code>namespace std {
template&lt;class T1, class T2&gt;
struct pair {
  [...]
  constexpr void swap(pair& p) noexcept(<i>see below</i>);

  <ins>friend constexpr bool operator==(const pair&, const pair&) = default;</ins>
  <ins>friend constexpr common_comparison_category_t&lt;<i>synth-3way-result</i>&lt;T1&gt;, <i>synth-3way-result</i>&lt;T2&gt;&gt;</ins>
  <ins>  operator<=>(const pair&, const pair&)</ins>
  <ins>  { <i>see below</i> }</ins>
};</code></pre>
</blockquote>

<blockquote>
<p>[...]
<pre><code>constexpr void swap(pair&amp; p) noexcept(<i>see below</i>);</code></pre>
<em>Requires</em>: <code class="language-cpp">first</code> shall be swappable with (15.5.3.2) <code class="language-cpp">p.first</code> and <code class="language-cpp">second</code> shall be swappable with <code class="language-cpp">p.second</code>.<br />
<em>Effects</em>: Swaps <code class="language-cpp">first</code> with <code class="language-cpp">p.first</code> and <code class="language-cpp">second</code> with <code class="language-cpp">p.second</code>.<br />
<em>Remarks</em>: The expression inside noexcept is equivalent to:
<code class="language-cpp">is_nothrow_swappable_v&lt;first_type&gt; &amp;&amp; is_nothrow_swappable_v&lt;second_type&gt;</code>
<pre><code><ins>friend constexpr common_comparison_category_t&lt;<i>synth-3way-result</i>&lt;T1&gt;, <i>synth-3way-result</i>&lt;T2&gt;&gt;</ins>
<ins>  operator&lt;=&gt;(const pair&amp; lhs, const pair&amp; rhs);</ins></code></pre>
<ins><em>Effects</em>: Equivalent to:</ins>
<blockquote class="ins"><pre><code>if (auto c = <i>synth-3way</i>(lhs.first, rhs.first); c != 0) return c;
return <i>synth-3way</i>(lhs.second, rhs.second);</code></pre></blockquote>
<ins><em>Remarks</em>:  This function is to be found via argument-dependent lookup only.</ins></p>
</blockquote>
<p>Change 20.4.3 [pairs.spec].</p>
<blockquote>
<p><pre><code><del>template&lt;class T1, class T2&gt;
constexpr bool operator==(const pair&lt;T1, T2&gt;&amp; x, const pair&lt;T1, T2&gt;&amp; y);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">x.first == y.first &amp;&amp; x.second == y.second</code>.</del>
<pre><code><del>template&lt;class T1, class T2&gt;
constexpr bool operator!=(const pair&lt;T1, T2&gt;&amp; x, const pair&lt;T1, T2&gt;&amp; y);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(x == y)</code>.</del>
<pre><code><del>template&lt;class T1, class T2&gt;
constexpr bool operator&lt;(const pair&lt;T1, T2&gt;&amp; x, const pair&lt;T1, T2&gt;&amp; y);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">x.first &lt; y.first || (!(y.first &lt; x.first) &amp;&amp; x.second &lt; y.second)</code>.</del>
<pre><code><del>template&lt;class T1, class T2&gt;
constexpr bool operator&gt;(const pair&lt;T1, T2&gt;&amp; x, const pair&lt;T1, T2&gt;&amp; y);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">y &lt; x</code></del>.
<pre><code><del>template&lt;class T1, class T2&gt;
constexpr bool operator&lt;=(const pair&lt;T1, T2&gt;&amp; x, const pair&lt;T1, T2&gt;&amp; y);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(y &lt; x)</code>.</del>
<pre><code><del>template&lt;class T1, class T2&gt;
constexpr bool operator&gt;=(const pair&lt;T1, T2&gt;&amp; x, const pair&lt;T1, T2&gt;&amp; y);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(x &lt; y)</code>.</del>
<pre><code>template&lt;class T1, class T2&gt;
constexpr void swap(pair&lt;T1, T2&gt;&amp; x, pair&lt;T1, T2&gt;&amp; y) noexcept(noexcept(x.swap(y)));</code></pre>
[...]</p>
</blockquote>
<p>Change 20.5.2 [tuple.syn]:</p>
<blockquote><pre><code>namespace std {
  // 20.5.3, class template tuple
  template&lt;class... Types&gt;
    class tuple;

  [...]  

  template&lt;class T, class... Types&gt;
    constexpr const T&& get(const tuple&lt;Types...&gt;&& t) noexcept;

  <del>// 20.5.3.8, relational operators</del>
  <del>template&lt;class... TTypes, class... UTypes&gt;</del>
    <del>constexpr bool operator==(const tuple&lt;TTypes...&gt;&, const tuple&lt;UTypes...&gt;&);</del>
  <del>template&lt;class... TTypes, class... UTypes&gt;</del>
    <del>constexpr bool operator!=(const tuple&lt;TTypes...&gt;&, const tuple&lt;UTypes...&gt;&);</del>
  <del>template&lt;class... TTypes, class... UTypes&gt;</del>
    <del>constexpr bool operator&lt;(const tuple&lt;TTypes...&gt;&, const tuple&lt;UTypes...&gt;&);</del>
  <del>template&lt;class... TTypes, class... UTypes&gt;</del>
    <del>constexpr bool operator&gt;(const tuple&lt;TTypes...&gt;&, const tuple&lt;UTypes...&gt;&);</del>
  <del>template&lt;class... TTypes, class... UTypes&gt;</del>
    <del>constexpr bool operator&lt;=(const tuple&lt;TTypes...&gt;&, const tuple&lt;UTypes...&gt;&);</del>
  <del>template&lt;class... TTypes, class... UTypes&gt;</del>
    <del>constexpr bool operator&gt;=(const tuple&lt;TTypes...&gt;&, const tuple&lt;UTypes...&gt;&);</del>

  // 20.5.3.9, allocator-related traits
  template&lt;class... Types, class Alloc&gt;
    struct uses_allocator&lt;tuple&lt;Types...&gt;, Alloc&gt;;  

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

<p>Change 20.5.3 [tuple.tuple]:</p>
<blockquote><pre><code>namespace std {
template<class... Types>
class tuple {
public:
  [...]

  // 20.5.3.3, tuple swap
  constexpr void swap(tuple&) noexcept(see below );

  <ins>// 20.5.3.8, tuple relational operators</ins>
  <ins>template&lt;class... UTypes&gt;</ins>
  <ins>  friend constexpr bool operator==(const tuple&, const tuple&lt;UTypes...&gt;&)</ins>  
  <ins>  { <i>see below</i> }</ins>
  <ins>template&lt;class... UTypes&gt;</ins>
  <ins>  friend constexpr common_comparison_category_t&lt;<i>synth-3way-result</i>&lt;Types, UTypes&gt;...&gt;</ins>
  <ins>    operator<=>(const tuple&, const tuple&lt;UTypes...&gt;&)</ins>
  <ins>  { <i>see below</i> }</ins>
};</code></pre></blockquote>

<p>Change 20.5.3.8 [tuple.rel]:</p>
<blockquote>
<p><pre><code><del>template&lt;class... TTypes, class... UTypes&gt;
  constexpr bool operator==(const tuple&lt;TTypes...&gt;&amp; t, const tuple&lt;UTypes...&gt;&amp; u);</del></code></pre>
<pre><code><ins>template&lt;class... UTypes&gt;</ins>
<ins>  friend constexpr bool operator==(const tuple&amp;, const tuple&lt;UTypes...&gt;&amp;)</ins></code></pre>
<em>Requires</em>: For all <code class="language-cpp">i</code>, where <code class="language-cpp">0 &lt;= i</code> and <code>i &lt; sizeof...(<del>TTypes</del> <ins>Types</ins>)</code>, <code class="language-cpp">get&lt;i&gt;(t) == get&lt;i&gt;(u)</code> is a well-formed expression returning a type that is convertible to <code class="language-cpp">bool</code>. <code>sizeof...(<del>TTypes</del> <ins>Types</ins>) == sizeof...(UTypes)</code>.<br />
<em>Returns</em>: <code class="language-cpp">true</code> if <code class="language-cpp">get&lt;i&gt;(t) == get&lt;i&gt;(u)</code> for all <code class="language-cpp">i</code>, otherwise <code class="language-cpp">false</code>. For any two zero-length tuples <code class="language-cpp">e</code> and <code class="language-cpp">f</code>, <code class="language-cpp">e == f</code> returns <code class="language-cpp">true</code>.<br />
<em>Effects</em>: The elementary comparisons are performed in order from the zeroth index upwards. No comparisons or element accesses are performed after the first equality comparison that evaluates to <code class="language-cpp">false</code>.<br />
<ins><em>Remarks</em>:  This function is to be found via argument-dependent lookup only.</ins>
<pre><code><del>template&lt;class... TTypes, class... UTypes&gt;<del>
<del>  constexpr bool operator!=(const tuple&lt;TTypes...&gt;&amp; t, const tuple&lt;UTypes...&gt;&amp; u);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(t == u)</code>.</del>
<pre><code><del>template&lt;class... TTypes, class... UTypes&gt;</del>
<del>constexpr bool operator&lt;(const tuple&lt;TTypes...&gt;&amp; t, const tuple&lt;UTypes...&gt;&amp; u);</del></code></pre>
<pre><code><ins>template&lt;class... UTypes&gt;</ins>
<ins>  friend constexpr common_comparison_category_t&lt;<i>synth-3way-result</i>&lt;Types, UTypes&gt;...&gt;</ins>
<ins>    operator&lt;=&gt;(const tuple&amp; t, const tuple&lt;UTypes...&gt;&amp; u);</ins></code></pre>
<em>Requires</em>: For all <code class="language-cpp">i</code>, where <code class="language-cpp">0 &lt;= i</code> and <code class="language-cpp">i &lt; sizeof...(Types)</code>, <del>both <code class="language-cpp">get&lt;i&gt;(t) &lt; get&lt;i&gt;(u)</code> and <code class="language-cpp">get&lt;i&gt;(u) &lt; get&lt;i&gt;(t)</code> are well-formed expressions returning types that are convertible to <code class="language-cpp">bool</code></del> <ins><code><i>synth-3way</i>(get&lt;i&gt;(t), get&lt;i&gt;(u))</code></ins> is a well-formed expression. <code>sizeof...(<del>TTypes</del> <ins>Types</ins>) == sizeof...(UTypes)</code>.<br />
<del><em>Returns</em>: The result of a lexicographical comparison between <code class="language-cpp">t</code> and <code class="language-cpp">u</code>. The result is defined as:
<code class="language-cpp">(bool)(get&lt;0&gt;(t) &lt; get&lt;0&gt;(u)) || (!(bool)(get&lt;0&gt;(u) &lt; get&lt;0&gt;(t)) &amp;&amp; ttail &lt; utail)</code>, where
<code>r<sub>tail</sub></code> for some tuple <code class="language-cpp">r</code> is a tuple containing all but the first element of <code class="language-cpp">r</code>. For any two zero-length tuples <code class="language-cpp">e</code> and <code class="language-cpp">f</code>, <code class="language-cpp">e &lt; f</code> returns <code class="language-cpp">false</code>.</del><br />
<ins><em>Effects</em>: Performs a lexicographical comparison between <code class="language-cpp">t</code> and <code class="language-cpp">u</code>. For any two zero-length tuples <code class="language-cpp">t</code> and <code class="language-cpp">u</code>, <code class="language-cpp">t &lt;=&gt; u</code> returns <code class="language-cpp">strong_ordering::equal</code>. Otherwise, equivalent to:</ins>
<blockquote class="ins"><pre><code>auto c = <i>synth-3way</i>(get&lt;0&gt;(t), get&lt;0&gt;(u));
return (c != 0) ? c : (t<sub>tail</sub> &lt;=&gt; u<sub>tail</sub>);</code></pre></blockquote>
<ins>where <code>r<sub>tail</sub></code> for some tuple <code class="language-cpp">r</code> is a tuple containing all but the first element of <code class="language-cpp">r</code>.</ins><br />
<ins><em>Remarks</em>:  This function is to be found via argument-dependent lookup only.</ins>
<pre><code><del>template&lt;class... TTypes, class... UTypes&gt;
constexpr bool operator&gt;(const tuple&lt;TTypes...&gt;&amp; t, const tuple&lt;UTypes...&gt;&amp; u);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">u &lt; t</code></del>.
<pre><code><del>template&lt;class... TTypes, class... UTypes&gt;
constexpr bool operator&lt;=(const tuple&lt;TTypes...&gt;&amp; t, const tuple&lt;UTypes...&gt;&amp; u);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(u &lt; t)</code></del>
<pre><code><del>template&lt;class... TTypes, class... UTypes&gt;
constexpr bool operator&gt;=(const tuple&lt;TTypes...&gt;&amp; t, const tuple&lt;UTypes...&gt;&amp; u);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(t &lt; u)</code></del><br />
<em>[Note:</em> The above definitions for comparison functions do not require <code>t<sub>tail</sub></code> (or <code>u<sub>tail</sub></code>) to be constructed. It may not even be possible, as <code class="language-cpp">t</code> and <code class="language-cpp">u</code> are not required to be copy constructible. Also, all comparison functions are short circuited; they do not perform element accesses beyond what is required to determine the result of the
comparison. <em>—end note]</em></p>
</blockquote>
<p>Change 20.6.2 [optional.syn]:</p>
<blockquote><pre><code>namespace std {
  [...]
  // [optional.bad.access], class bad_optional_access
  class bad_optional_access;

<del>  // [optional.relops], relational operators
  template&lt;class T, class U&gt;
    constexpr bool operator==(const optional&lt;T&gt;&, const optional&lt;U&gt;&);
  template&lt;class T, class U&gt;
    constexpr bool operator!=(const optional&lt;T&gt;&, const optional&lt;U&gt;&);
  template&lt;class T, class U&gt;
    constexpr bool operator&lt;(const optional&lt;T&gt;&, const optional&lt;U&gt;&);
  template&lt;class T, class U&gt;
    constexpr bool operator&gt;(const optional&lt;T&gt;&, const optional&lt;U&gt;&);
  template&lt;class T, class U&gt;
    constexpr bool operator&lt;=(const optional&lt;T&gt;&, const optional&lt;U&gt;&);
  template&lt;class T, class U&gt;
    constexpr bool operator&gt;=(const optional&lt;T&gt;&, const optional&lt;U&gt;&);

  // [optional.nullops], comparison with nullopt
  template&lt;class T&gt; constexpr bool operator==(const optional&lt;T&gt;&, nullopt_t) noexcept;
  template&lt;class T&gt; constexpr bool operator==(nullopt_t, const optional&lt;T&gt;&) noexcept;
  template&lt;class T&gt; constexpr bool operator!=(const optional&lt;T&gt;&, nullopt_t) noexcept;
  template&lt;class T&gt; constexpr bool operator!=(nullopt_t, const optional&lt;T&gt;&) noexcept;
  template&lt;class T&gt; constexpr bool operator&lt;(const optional&lt;T&gt;&, nullopt_t) noexcept;
  template&lt;class T&gt; constexpr bool operator&lt;(nullopt_t, const optional&lt;T&gt;&) noexcept;
  template&lt;class T&gt; constexpr bool operator&gt;(const optional&lt;T&gt;&, nullopt_t) noexcept;
  template&lt;class T&gt; constexpr bool operator&gt;(nullopt_t, const optional&lt;T&gt;&) noexcept;
  template&lt;class T&gt; constexpr bool operator&lt;=(const optional&lt;T&gt;&, nullopt_t) noexcept;
  template&lt;class T&gt; constexpr bool operator&lt;=(nullopt_t, const optional&lt;T&gt;&) noexcept;
  template&lt;class T&gt; constexpr bool operator&gt;=(const optional&lt;T&gt;&, nullopt_t) noexcept;
  template&lt;class T&gt; constexpr bool operator&gt;=(nullopt_t, const optional&lt;T&gt;&) noexcept;

  // [optional.comp_with_t], comparison with T
  template&lt;class T, class U&gt; constexpr bool operator==(const optional&lt;T&gt;&, const U&);
  template&lt;class T, class U&gt; constexpr bool operator==(const T&, const optional&lt;U&gt;&);
  template&lt;class T, class U&gt; constexpr bool operator!=(const optional&lt;T&gt;&, const U&);
  template&lt;class T, class U&gt; constexpr bool operator!=(const T&, const optional&lt;U&gt;&);
  template&lt;class T, class U&gt; constexpr bool operator&lt;(const optional&lt;T&gt;&, const U&);
  template&lt;class T, class U&gt; constexpr bool operator&lt;(const T&, const optional&lt;U&gt;&);
  template&lt;class T, class U&gt; constexpr bool operator&gt;(const optional&lt;T&gt;&, const U&);
  template&lt;class T, class U&gt; constexpr bool operator&gt;(const T&, const optional&lt;U&gt;&);
  template&lt;class T, class U&gt; constexpr bool operator&lt;=(const optional&lt;T&gt;&, const U&);
  template&lt;class T, class U&gt; constexpr bool operator&lt;=(const T&, const optional&lt;U&gt;&);
  template&lt;class T, class U&gt; constexpr bool operator&gt;=(const optional&lt;T&gt;&, const U&);
  template&lt;class T, class U&gt; constexpr bool operator&gt;=(const T&, const optional&lt;U&gt;&);</del>

  // [optional.specalg], specialized algorithms
  template&lt;class T&gt;
    void swap(optional&lt;T&gt;&, optional&lt;T&gt;&) noexcept(see below);
  [...]
}</code></pre></blockquote>

<p>Change 20.6.3 [optional.optional]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class T&gt;
  class optional {
  public:
    [...]

    // [optional.mod], modifiers
    void reset() noexcept;

    <ins>// [optional.relops], relational operators</ins>
    <ins>template&lt;class U&gt;</ins>
    <ins>  friend constexpr bool operator==(const optional&, const optional&lt;U&gt;&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt;</ins>
    <ins>  friend constexpr bool operator!=(const optional&, const optional&lt;U&gt;&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt;</ins>
    <ins>  friend constexpr bool operator&lt;(const optional&, const optional&lt;U&gt;&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt;</ins>
    <ins>  friend constexpr bool operator&gt;(const optional&, const optional&lt;U&gt;&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt;</ins>
    <ins>  friend constexpr bool operator&lt;=(const optional&, const optional&lt;U&gt;&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt;</ins>
    <ins>  friend constexpr bool operator&gt;=(const optional&, const optional&lt;U&gt;&) { <i>see below</i> }</ins>
    <ins>template&lt;ThreeWayComparableWith&lt;T&gt; U&gt;</ins>
    <ins>  friend constexpr compare_three_way_result_t&lt;T,U&gt;</ins>
    <ins>    operator&lt;=&gt;(const optional&, const optional&lt;U&gt;&)</ins>
    <ins>    { <i>see below</i> }</ins>

    <ins>// comparison with nullopt</ins>
    <ins>friend constexpr bool operator==(const optional& x, nullopt_t) { return !x; }</ins>
    <ins>friend constexpr strong_ordering operator&lt;=&gt;(const optional& x, nullopt_t) { return bool(x) &lt;=&gt; false; }</ins>

    <ins>// [optional.comp_with_t], comparison with T</ins>
    <ins>template&lt;class U&gt; friend constexpr bool operator==(const optional&, const U&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt; friend constexpr bool operator==(const U&, const optional&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt; friend constexpr bool operator!=(const optional&, const U&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt; friend constexpr bool operator!=(const U&, const optional&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt; friend constexpr bool operator&lt;(const optional&, const U&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt; friend constexpr bool operator&lt;(const U&, const optional&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt; friend constexpr bool operator&gt;(const optional&, const U&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt; friend constexpr bool operator&gt;(const U&, const optional&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt; friend constexpr bool operator&lt;=(const optional&, const U&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt; friend constexpr bool operator&lt;=(const U&, const optional&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt; friend constexpr bool operator&gt;=(const optional&, const U&) { <i>see below</i> }</ins>
    <ins>template&lt;class U&gt; friend constexpr bool operator&gt;=(const U&, const optional&) { <i>see below</i> }</ins>
    <ins>template&lt;ThreeWayComparableWith&lt;T&gt; U&gt;</ins>
    <ins>  friend constexpr compare_three_way_result_t&lt;T,U&gt;</ins>
    <ins>    operator&lt;=&gt;(const optional&, const U&)</ins>
    <ins>    { <i>see below</i> }</ins>

  private:
    T *val;         // exposition only
  };
}</code></pre></blockquote>

<p>Change 20.6.6 [optional.relops]:</p>
<blockquote>
<p><pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator==(const optional<del>&lt;T&gt;</del>&amp; x, const optional&lt;U&gt;&amp; y);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">*x == *y</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>. [<em>Note</em>: <code class="language-cpp">T</code> need not be <code class="language-cpp">Cpp17EqualityComparable</code>. —<em>end note</em>]<br />
<em>Returns</em>: If <code class="language-cpp">bool(x) != bool(y)</code>, <code class="language-cpp">false</code>; otherwise if <code class="language-cpp">bool(x) == false</code>, <code class="language-cpp">true</code>; otherwise <code class="language-cpp">*x == *y</code>.<br />
<em>Remarks</em>: Specializations of this function template for which <code class="language-cpp">*x == *y</code> is a core constant expression shall be constexpr functions. <ins>This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator!=(const optional<del>&lt;T&gt;</del>&amp; x, const optional&lt;U&gt;&amp; y);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">*x != *y</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: If <code class="language-cpp">bool(x) != bool(y)</code>, <code class="language-cpp">true</code>; otherwise, if <code class="language-cpp">bool(x) == false</code>, <code class="language-cpp">false</code>; otherwise <code class="language-cpp">*x != *y</code>.<br />
<em>Remarks</em>: Specializations of this function template for which <code class="language-cpp">*x != *y</code> is a core constant expression shall be constexpr functions. <ins>This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator&lt;(const optional<del>&lt;T&gt;</del>&amp; x, const optional&lt;U&gt;&amp; y);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: <code class="language-cpp">*x &lt; *y</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: If <code class="language-cpp">!y</code>, <code class="language-cpp">false</code>; otherwise, if <code class="language-cpp">!x</code>, <code class="language-cpp">true</code>; otherwise <code class="language-cpp">*x &lt; *y</code>.<br />
<em>Remarks</em>: Specializations of this function template for which <code class="language-cpp">*x &lt; *y</code> is a core constant expression shall be constexpr functions. <ins>This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator&gt;(const optional<del>&lt;T&gt;</del>&amp; x, const optional&lt;U&gt;&amp; y);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">*x &gt; *y</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: If <code class="language-cpp">!x</code>, <code class="language-cpp">false</code>; otherwise, if <code class="language-cpp">!y</code>, <code class="language-cpp">true</code>; otherwise <code class="language-cpp">*x &gt; *y</code>.<br />
<em>Remarks</em>: Specializations of this function template for which <code class="language-cpp">*x &gt; *y</code> is a core constant expression shall be constexpr functions. <ins>This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator&lt;=(const optional<del>&lt;T&gt;</del>&amp; x, const optional&lt;U&gt;&amp; y);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">*x &lt;= *y</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: If <code class="language-cpp">!x</code>, <code class="language-cpp">true</code>; otherwise, if <code class="language-cpp">!y</code>, <code class="language-cpp">false</code>; otherwise <code class="language-cpp">*x &lt;= *y</code>.<br />
<em>Remarks</em>: Specializations of this function template for which <code class="language-cpp">*x &lt;= *y</code> is a core constant expression shall be constexpr functions. <ins>This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T</del>, class U&gt; <ins>friend </ins>constexpr bool operator&gt;=(const optional<del>&lt;T&gt;</del>&amp; x, const optional&lt;U&gt;&amp; y);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">*x &gt;= *y</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: If <code class="language-cpp">!y</code>, <code class="language-cpp">true</code>; otherwise, if <code class="language-cpp">!x</code>, <code class="language-cpp">false</code>; otherwise <code class="language-cpp">*x &gt;= *y</code>.<br />
<em>Remarks</em>: Specializations of this function template for which <code class="language-cpp">*x &gt;= *y</code> is a core constant expression shall be constexpr functions. This function is to be found via argument-dependent lookup only.<ins>
<pre><code><ins>template&lt;ThreeWayComparableWith&lt;T&gt; U&gt;</ins>
<ins>  friend constexpr compare_three_way_result_t&lt;T,U&gt;</ins>
<ins>    operator&lt;=&gt;(const optional&amp; x, const optional&lt;U&gt;&amp; y);</ins></code></pre>
<ins><em>Returns</em>: If <code class="language-cpp">x &amp;&amp; y</code>, <code class="language-cpp">*x &lt;=&gt; *y</code>; otherwise <code class="language-cpp">bool(x) &lt;=&gt; bool(y)</code>.</ins><br />
<ins><em>Remarks</em>: Specializations of this function template for which <code class="language-cpp">*x &lt;=&gt; *y</code> is a core constant expression shall be <code class="language-cpp">constexpr</code> functions. This function is to be found via argument-dependent lookup only.</ins></p>
</blockquote>
<p>Remove 20.6.7 [optional.nullops] (it is now fully expressed by the two hidden friends defined in the header):</p>
<blockquote>
<p><pre><code><del>template&lt;class T&gt; constexpr bool operator==(const optional&lt;T&gt;&amp; x, nullopt_t) noexcept;</del>
<del>template&lt;class T&gt; constexpr bool operator==(nullopt_t, const optional&lt;T&gt;&amp; x) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!x</code>.</del>
<pre><code><del>template&lt;class T&gt; constexpr bool operator!=(const optional&lt;T&gt;&amp; x, nullopt_t) noexcept;
template&lt;class T&gt; constexpr bool operator!=(nullopt_t, const optional&lt;T&gt;&amp; x) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">bool(x)</code>.</del>
[...]</p>
</blockquote>
<p>Change 20.6.8 [optional.comp_with_t]:</p>
<blockquote>
<p><pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator==(const optional<del>&lt;T&gt;</del>&amp; x, const U&amp; v);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">*x == v</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>. [<em>Note</em>: <code class="language-cpp">T</code> need not be <code class="language-cpp">Cpp17EqualityComparable</code>. —<em>end note</em>]<br />
<em>Effects</em>: Equivalent to: <code class="language-cpp">return bool(x) ? *x == v : false;</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator==(const <del>T</del><ins>U</ins>&amp; v, const optional<del>&lt;U&gt;</del>&amp; x);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">v == *x</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Effects</em>: Equivalent to: <code class="language-cpp">return bool(x) ? v == *x : false;</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator!=(const optional<del>&lt;T&gt;</del>&amp; x, const U&amp; v);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">*x != v</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Effects</em>: Equivalent to: <code class="language-cpp">return bool(x) ? *x != v : true;</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator!=(const <del>T</del><ins>U</ins>&amp; v, const optional<del>&lt;U&gt;</del>&amp; x);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">v != *x</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Effects</em>: Equivalent to: <code class="language-cpp">return bool(x) ? v != *x : true;</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator&lt;(const optional<del>&lt;T&gt;</del>&amp; x, const U&amp; v);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">*x &lt; v</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Effects</em>: Equivalent to: <code class="language-cpp">return bool(x) ? *x &lt; v : true;</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator&lt;(const <del>T</del><ins>U</ins>&amp; v, const optional<del>&lt;U&gt;</del>&amp; x);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">v &lt; *x</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Effects</em>: Equivalent to: <code class="language-cpp">return bool(x) ? v &lt; *x : false;</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator&gt;(const optional<del>&lt;T&gt;</del>&amp; x, const U&amp; v);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">*x &gt; v</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Effects</em>: Equivalent to: <code class="language-cpp">return bool(x) ? *x &gt; v : false;</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator&gt;(const <del>T</del><ins>U</ins>&amp; v, const optional<del>&lt;U&gt;</del>&amp; x);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">v &gt; *x</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Effects</em>: Equivalent to: <code class="language-cpp">return bool(x) ? v &gt; *x : true;</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator&lt;=(const optional<del>&lt;T&gt;</del>&amp; x, const U&amp; v);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">*x &lt;= v</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Effects</em>: Equivalent to: <code class="language-cpp">return bool(x) ? *x &lt;= v : true;</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator&lt;=(const <del>T</del><ins>U</ins>&amp; v, const optional<del>&lt;U&gt;</del>&amp; x);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">v &lt;= *x</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Effects</em>: Equivalent to: <code class="language-cpp">return bool(x) ? v &lt;= *x : false;</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator&gt;=(const optional<del>&lt;T&gt;</del>&amp; x, const U&amp; v);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">*x &gt;= v</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Effects</em>: Equivalent to: <code class="language-cpp">return bool(x) ? *x &gt;= v : false;</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T, </del>class U&gt; <ins>friend </ins>constexpr bool operator&gt;=(const <del>T</del><ins>U</ins>&amp; v, const optional<del>&lt;U&gt;</del>&amp; x);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: The expression <code class="language-cpp">v &gt;= *x</code> shall be well-formed and its result shall be convertible to <code class="language-cpp">bool</code>.<br />
<em>Effects</em>: Equivalent to: <code class="language-cpp">return bool(x) ? v &gt;= *x : true;</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><ins>template&lt;ThreeWayComparableWith&lt;T&gt; U&gt;</ins>
<ins>  friend constexpr compare_three_way_result_t&lt;T,U&gt;</ins>
<ins>    operator&lt;=&gt;(const optional&amp; x, const U&amp; v);</ins></code></pre>
<ins><em>Effects</em>: Equivalent to: <code class="language-cpp">return bool(x) ? *x &lt;=&gt; v : strong_ordering::less;</code></ins><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins></p>
</blockquote>
<p>Change 20.7.2 [variant.syn]:</p>
<blockquote><pre><code>namespace std {
  [...]
  template&lt;class T, class... Types&gt;
    constexpr add_pointer_t&lt;T&gt;
      get_if(variant&lt;Types...&gt;*) noexcept;
  template&lt;class T, class... Types&gt;
    constexpr add_pointer_t&lt;const T&gt;
      get_if(const variant&lt;Types...&gt;*) noexcept;

  // [variant.relops], relational operators
<del>  template&lt;class... Types&gt;
    constexpr bool operator==(const variant&lt;Types...&gt;&, const variant&lt;Types...&gt;&);
  template&lt;class... Types&gt;
    constexpr bool operator!=(const variant&lt;Types...&gt;&, const variant&lt;Types...&gt;&);
  template&lt;class... Types&gt;
    constexpr bool operator&lt;(const variant&lt;Types...&gt;&, const variant&lt;Types...&gt;&);
  template&lt;class... Types&gt;
    constexpr bool operator&gt;(const variant&lt;Types...&gt;&, const variant&lt;Types...&gt;&);
  template&lt;class... Types&gt;
    constexpr bool operator&lt;=(const variant&lt;Types...&gt;&, const variant&lt;Types...&gt;&);
  template&lt;class... Types&gt;
    constexpr bool operator&gt;=(const variant&lt;Types...&gt;&, const variant&lt;Types...&gt;&);</del>

  // [variant.visit], visitation
  [...]  

  // [variant.monostate], class monostate
  struct monostate;

<del>  // [variant.monostate.relops], monostate relational operators
  constexpr bool operator==(monostate, monostate) noexcept;
  constexpr bool operator!=(monostate, monostate) noexcept;
  constexpr bool operator&lt;(monostate, monostate) noexcept;
  constexpr bool operator&gt;(monostate, monostate) noexcept;
  constexpr bool operator&lt;=(monostate, monostate) noexcept;
  constexpr bool operator&gt;=(monostate, monostate) noexcept;</del>

  // [variant.specalg], specialized algorithms
  template&lt;class... Types&gt;
    void swap(variant&lt;Types...&gt;&, variant&lt;Types...&gt;&) noexcept(<i>see below</i>);
  [...]
}</code></pre></blockquote>

<p>Change 20.7.3 [variant.variant]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class... Types&gt;
  class variant {
  public:
    [...]

    // [variant.swap], swap
    void swap(variant&) noexcept(see below);

    <ins>// [variant.relops], relational operators</ins>
    <ins>friend constexpr bool operator==(const variant&, const variant&) { <i>see below</i> }</ins>
    <ins>friend constexpr bool operator!=(const variant&, const variant&) { <i>see below</i> }</ins>
    <ins>friend constexpr bool operator&lt;(const variant&, const variant&) { <i>see below</i> }</ins>
    <ins>friend constexpr bool operator&gt;(const variant&, const variant&) { <i>see below</i> }</ins>
    <ins>friend constexpr bool operator&lt;=(const variant&, const variant&) { <i>see below</i> }</ins>
    <ins>friend constexpr bool operator&gt;=(const variant&, const variant&) { <i>see below</i> }</ins>
    <ins>friend constexpr common_comparison_category_t&lt;compare_three_way_result_t&lt;Types&gt;...&gt;</ins>
    <ins>  operator&lt;=&gt;(const variant&, const variant&)</ins>
    <ins>    requires (ThreeWayComparable&lt;Types&gt; && ...)</ins>
    <ins>    { <i>see below</i> }</ins>
  };
}</code></pre></blockquote>

<p>Change 20.7.6 [variant.relops]:</p>
<blockquote>
<p><pre><code><del>template&lt;class... Types&gt;</del>
<ins>friend </ins>constexpr bool operator==(const variant<del>&lt;Types...&gt;</del>&amp; v, const variant<del>&lt;Types...&gt;</del>&amp; w);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: <code class="language-cpp">get&lt;i&gt;(v) == get&lt;i&gt;(w)</code> is a valid expression returning a type that is convertible to <code class="language-cpp">bool</code>, for all <code class="language-cpp">i</code>.<br />
<em>Returns</em>: If <code class="language-cpp">v.index() != w.index()</code>, <code class="language-cpp">false</code>; otherwise if <code class="language-cpp">v.valueless_by_exception()</code>, <code class="language-cpp">true</code>; otherwise <code class="language-cpp">get&lt;i&gt;(v) == get&lt;i&gt;(w)</code> with <code class="language-cpp">i</code> being <code class="language-cpp">v.index()</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><del>template&lt;class... Types&gt;</del>
<ins>friend </ins>constexpr bool operator!=(const variant<del>&lt;Types...&gt;</del>&amp; v, const variant<del>&lt;Types...&gt;</del>&amp; w);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: <code class="language-cpp">get&lt;i&gt;(v) != get&lt;i&gt;(w)</code> is a valid expression returning a type that is convertible to <code class="language-cpp">bool</code>, for all <code class="language-cpp">i</code>.
<em>Returns</em>: If <code class="language-cpp">v.index() != w.index()</code>, <code class="language-cpp">true</code>; otherwise if <code class="language-cpp">v.valueless_by_exception()</code>, <code class="language-cpp">false</code>; otherwise <code class="language-cpp">get&lt;i&gt;(v) != get&lt;i&gt;(w)</code> with <code class="language-cpp">i</code> being <code class="language-cpp">v.index()</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><del>template&lt;class... Types&gt;</del>
<ins>friend </ins>constexpr bool operator&lt;(const variant<del>&lt;Types...&gt;</del>&amp; v, const variant<del>&lt;Types...&gt;</del>&amp; w);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: <code class="language-cpp">get&lt;i&gt;(v) &lt; get&lt;i&gt;(w)</code> is a valid expression returning a type that is convertible to <code class="language-cpp">bool</code>, for all <code class="language-cpp">i</code>.<br />
<em>Returns</em>: If <code class="language-cpp">w.valueless_by_exception()</code>, <code class="language-cpp">false</code>; otherwise if <code class="language-cpp">v.valueless_by_exception()</code>, <code class="language-cpp">true</code>; otherwise, if <code class="language-cpp">v.index() &lt; w.index()</code>, <code class="language-cpp">true</code>; otherwise if <code class="language-cpp">v.index() &gt; w.index()</code>, <code class="language-cpp">false</code>; otherwise <code class="language-cpp">get&lt;i&gt;(v) &lt; get&lt;i&gt;(w)</code> with <code class="language-cpp">i</code> being <code class="language-cpp">v.index()</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><del>template&lt;class... Types&gt;</del>
<ins>friend </ins>constexpr bool operator&gt;(const variant<del>&lt;Types...&gt;</del>&amp; v, const variant<del>&lt;Types...&gt;</del>&amp; w);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: <code class="language-cpp">get&lt;i&gt;(v) &gt; get&lt;i&gt;(w)</code> is a valid expression returning a type that is convertible to <code class="language-cpp">bool</code>, for all <code class="language-cpp">i</code>.<br />
<em>Returns</em>: If <code class="language-cpp">v.valueless_by_exception()</code>, <code class="language-cpp">false</code>; otherwise if <code class="language-cpp">w.valueless_by_exception()</code>, <code class="language-cpp">true</code>; otherwise, if <code class="language-cpp">v.index() &gt; w.index()</code>, <code class="language-cpp">true</code>; otherwise if <code class="language-cpp">v.index() &lt; w.index()</code>, <code class="language-cpp">false</code>; otherwise <code class="language-cpp">get&lt;i&gt;(v) &gt; get&lt;i&gt;(w)</code> with <code class="language-cpp">i</code> being <code class="language-cpp">v.index()</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><del>template&lt;class... Types&gt;</del>
<ins>friend </ins>constexpr bool operator&lt;=(const variant<del>&lt;Types...&gt;</del>&amp; v, const variant<del>&lt;Types...&gt;</del>&amp; w);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: <code class="language-cpp">get&lt;i&gt;(v) &lt;= get&lt;i&gt;(w)</code> is a valid expression returning a type that is convertible to <code class="language-cpp">bool</code>, for all <code class="language-cpp">i</code>.<br />
<em>Returns</em>: If <code class="language-cpp">v.valueless_by_exception()</code>, <code class="language-cpp">true</code>; otherwise if <code class="language-cpp">w.valueless_by_exception()</code>, <code class="language-cpp">false</code>; otherwise, if <code class="language-cpp">v.index() &lt; w.index()</code>, <code class="language-cpp">true</code>; otherwise if <code class="language-cpp">v.index() &gt; w.index()</code>, <code class="language-cpp">false</code>; otherwise <code class="language-cpp">get&lt;i&gt;(v) &lt;= get&lt;i&gt;(w)</code> with <code class="language-cpp">i</code> being <code class="language-cpp">v.index()</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><del>template&lt;class... Types&gt;</del>
<ins>friend </ins>constexpr bool operator&gt;=(const variant<del>&lt;Types...&gt;</del>&amp; v, const variant<del>&lt;Types...&gt;</del>&amp; w);</code></pre>
<del><em>Requires</em></del><ins><em>Mandates</em></ins>: <code class="language-cpp">get&lt;i&gt;(v) &gt;= get&lt;i&gt;(w)</code> is a valid expression returning a type that is convertible to <code class="language-cpp">bool</code>, for all <code class="language-cpp">i</code>.<br />
<em>Returns</em>: If <code class="language-cpp">w.valueless_by_exception()</code>, <code class="language-cpp">true</code>; otherwise if <code class="language-cpp">v.valueless_by_exception()</code>, <code class="language-cpp">false</code>; otherwise, if <code class="language-cpp">v.index() &gt; w.index()</code>, <code class="language-cpp">true</code>; otherwise if <code class="language-cpp">v.index() &lt; w.index()</code>, <code class="language-cpp">false</code>; otherwise <code class="language-cpp">get&lt;i&gt;(v) &gt;= get&lt;i&gt;(w)</code> with <code class="language-cpp">i</code> being <code class="language-cpp">v.index()</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><ins>constexpr common_comparison_category_t&lt;compare_three_way_result_t&lt;Types&gt;...&gt;</ins>
<ins>  friend operator&lt;=&gt;(const variant&amp; v, const variant&amp; w)</ins>
<ins>    requires (ThreeWayComparable&lt;Types&gt; &amp;&amp; ...);</ins></code></pre>
<ins><em>Returns</em>: Let <code class="language-cpp">c</code> be <code class="language-cpp">(v.index() + 1) &lt;=&gt; (w.index() + 1)</code>. If <code class="language-cpp">c != 0</code>, <code class="language-cpp">c</code>. Otherwise, <code class="language-cpp">get&lt;i&gt;(v) &lt;=&gt; get&lt;i&gt;(w)</code> with <code class="language-cpp">i</code> being <code class="language-cpp">v.index()</code>.</ins><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins></p>
</blockquote>
<p>Change 20.7.8 [variant.monostate]:</p>
<blockquote><pre><code><del>struct monostate{};</del>
<ins>struct monostate {
  friend constexpr bool operator==(monostate, monostate) noexcept = default;
  friend constexpr strong_ordering operator<=>(monostate, monostate) noexcept = default;
};</ins></code></pre>

<ins>[<i>Note</i>: monostate objects have only a single state; they thus always compare equal. —<i>end note</i>]</ins></blockquote>

<p>Remove 20.7.9 [variant.monostate.relops]:</p>
<blockquote><pre><code><del>constexpr bool operator==(monostate, monostate) noexcept { return true; }</del>
<del>constexpr bool operator!=(monostate, monostate) noexcept { return false; }</del>
<del>constexpr bool operator<(monostate, monostate) noexcept { return false; }</del>
<del>constexpr bool operator>(monostate, monostate) noexcept { return false; }</del>
<del>constexpr bool operator<=(monostate, monostate) noexcept { return true; }</del>
<del>constexpr bool operator>=(monostate, monostate) noexcept { return true; }</del></code></pre>

<del>[<i>Note</i>: monostate objects have only a single state; they thus always compare equal. —<i>end note</i>]</del></blockquote>

<p>Change 20.9.2 [template.bitset]:</p>
<blockquote><pre><code>namespace std {
  template&lt;size_t N&gt; class bitset {
  public:
    [...]
    constexpr size_t size() const noexcept;
    bool operator==(const bitset&lt;N&gt;& rhs) const noexcept;
    <del>bool operator!=(const bitset&lt;N&gt;& rhs) const noexcept;</del>
    bool test(size_t pos) const;
    [...]
  };
}</code></pre></blockquote>

<p>Change 20.9.2.2 [bitset.members]:</p>
<blockquote>
<p><pre><code>bool operator==(const bitset&lt;N&gt;&amp; rhs) const noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">true</code> if the value of each bit in <code class="language-cpp">*this</code> equals the value of the corresponding bit in <code class="language-cpp">rhs</code>.
<del><pre><code>bool operator!=(const bitset&lt;N&gt;&amp; rhs) const noexcept;</code></pre></del>
<del><em>Returns</em>: <code class="language-cpp">true</code> if <code class="language-cpp">!(*this == rhs)</code>.</del></blockquote></p>
</blockquote>
<p>Change 20.10.2 [memory.syn]:</p>
<blockquote><pre><code>namespace std {
  [...]
  // [default.allocator], the default allocator
  template&lt;class T&gt; class allocator;
<del>  template&lt;class T, class U&gt;
    bool operator==(const allocator&lt;T&gt;&, const allocator&lt;U&gt;&) noexcept;
  template&lt;class T, class U&gt;
    bool operator!=(const allocator&lt;T&gt;&, const allocator&lt;U&gt;&) noexcept;</del>
  [...]
  template&lt;class T, class D&gt; 
    void swap(unique_ptr&lt;T, D&gt;& x, unique_ptr&lt;T, D&gt;& y) noexcept;

<del>  template&lt;class T1, class D1, class T2, class D2&gt;
    bool operator==(const unique_ptr&lt;T1, D1&gt;& x, const unique_ptr&lt;T2, D2&gt;& y);
  template&lt;class T1, class D1, class T2, class D2&gt;
    bool operator!=(const unique_ptr&lt;T1, D1&gt;& x, const unique_ptr&lt;T2, D2&gt;& y);
  template&lt;class T1, class D1, class T2, class D2&gt;
    bool operator&lt;(const unique_ptr&lt;T1, D1&gt;& x, const unique_ptr&lt;T2, D2&gt;& y);
  template&lt;class T1, class D1, class T2, class D2&gt;
    bool operator&gt;(const unique_ptr&lt;T1, D1&gt;& x, const unique_ptr&lt;T2, D2&gt;& y);
  template&lt;class T1, class D1, class T2, class D2&gt;
    bool operator&lt;=(const unique_ptr&lt;T1, D1&gt;& x, const unique_ptr&lt;T2, D2&gt;& y);
  template&lt;class T1, class D1, class T2, class D2&gt;
    bool operator&gt;=(const unique_ptr&lt;T1, D1&gt;& x, const unique_ptr&lt;T2, D2&gt;& y);

  template&lt;class T, class D&gt;
    bool operator==(const unique_ptr&lt;T, D&gt;& x, nullptr_t) noexcept;
  template&lt;class T, class D&gt;
    bool operator==(nullptr_t, const unique_ptr&lt;T, D&gt;& y) noexcept;
  template&lt;class T, class D&gt;
    bool operator!=(const unique_ptr&lt;T, D&gt;& x, nullptr_t) noexcept;
  template&lt;class T, class D&gt;
    bool operator!=(nullptr_t, const unique_ptr&lt;T, D&gt;& y) noexcept;
  template&lt;class T, class D&gt;
    bool operator&lt;(const unique_ptr&lt;T, D&gt;& x, nullptr_t);
  template&lt;class T, class D&gt;
    bool operator&lt;(nullptr_t, const unique_ptr&lt;T, D&gt;& y);
  template&lt;class T, class D&gt;
    bool operator&gt;(const unique_ptr&lt;T, D&gt;& x, nullptr_t);
  template&lt;class T, class D&gt;
    bool operator&gt;(nullptr_t, const unique_ptr&lt;T, D&gt;& y);
  template&lt;class T, class D&gt;
    bool operator&lt;=(const unique_ptr&lt;T, D&gt;& x, nullptr_t);
  template&lt;class T, class D&gt;
    bool operator&lt;=(nullptr_t, const unique_ptr&lt;T, D&gt;& y);
  template&lt;class T, class D&gt;
    bool operator&gt;=(const unique_ptr&lt;T, D&gt;& x, nullptr_t);
  template&lt;class T, class D&gt;
    bool operator&gt;=(nullptr_t, const unique_ptr&lt;T, D&gt;& y);</del>

  template&lt;class E, class T, class Y, class D&gt;
    basic_ostream&lt;E, T&gt;& operator&lt;&lt;(basic_ostream&lt;E, T&gt;& os, const unique_ptr&lt;Y, D&gt;& p);  
  [...]
  <del>// [util.smartptr.shared.cmp], shared_ptr comparisons</del>
<del>  template&lt;class T, class U&gt;
    bool operator==(const shared_ptr&lt;T&gt;& a, const shared_ptr&lt;U&gt;& b) noexcept;
  template&lt;class T, class U&gt;
    bool operator!=(const shared_ptr&lt;T&gt;& a, const shared_ptr&lt;U&gt;& b) noexcept;
  template&lt;class T, class U&gt;
    bool operator&lt;(const shared_ptr&lt;T&gt;& a, const shared_ptr&lt;U&gt;& b) noexcept;
  template&lt;class T, class U&gt;
    bool operator&gt;(const shared_ptr&lt;T&gt;& a, const shared_ptr&lt;U&gt;& b) noexcept;
  template&lt;class T, class U&gt;
    bool operator&lt;=(const shared_ptr&lt;T&gt;& a, const shared_ptr&lt;U&gt;& b) noexcept;
  template&lt;class T, class U&gt;
    bool operator&gt;=(const shared_ptr&lt;T&gt;& a, const shared_ptr&lt;U&gt;& b) noexcept;

  template&lt;class T&gt;
    bool operator==(const shared_ptr&lt;T&gt;& x, nullptr_t) noexcept;
  template&lt;class T&gt;
    bool operator==(nullptr_t, const shared_ptr&lt;T&gt;& y) noexcept;
  template&lt;class T&gt;
    bool operator!=(const shared_ptr&lt;T&gt;& x, nullptr_t) noexcept;
  template&lt;class T&gt;
    bool operator!=(nullptr_t, const shared_ptr&lt;T&gt;& y) noexcept;
  template&lt;class T&gt;
    bool operator&lt;(const shared_ptr&lt;T&gt;& x, nullptr_t) noexcept;
  template&lt;class T&gt;
    bool operator&lt;(nullptr_t, const shared_ptr&lt;T&gt;& y) noexcept;
  template&lt;class T&gt;
    bool operator&gt;(const shared_ptr&lt;T&gt;& x, nullptr_t) noexcept;
  template&lt;class T&gt;
    bool operator&gt;(nullptr_t, const shared_ptr&lt;T&gt;& y) noexcept;
  template&lt;class T&gt;
    bool operator&lt;=(const shared_ptr&lt;T&gt;& x, nullptr_t) noexcept;
  template&lt;class T&gt;
    bool operator&lt;=(nullptr_t, const shared_ptr&lt;T&gt;& y) noexcept;
  template&lt;class T&gt;
    bool operator&gt;=(const shared_ptr&lt;T&gt;& x, nullptr_t) noexcept;
  template&lt;class T&gt;
    bool operator&gt;=(nullptr_t, const shared_ptr&lt;T&gt;& y) noexcept;</del>

  // [util.smartptr.shared.spec], shared_ptr specialized algorithms
  template&lt;class T&gt;
    void swap(shared_ptr&lt;T&gt;& a, shared_ptr&lt;T&gt;& b) noexcept;
  [...]    
}</code></pre></blockquote>

<p>Change 20.10.10 [default.allocator]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class T&gt; class allocator {
   public:
    using value_type      = T;
    using size_type       = size_t;
    using difference_type = ptrdiff_t;
    using propagate_on_container_move_assignment = true_type;
    using is_always_equal = true_type;

    constexpr allocator() noexcept;
    constexpr allocator(const allocator&) noexcept;
    template&lt;class U&gt; constexpr allocator(const allocator&lt;U&gt;&) noexcept;
    ~allocator();
    allocator& operator=(const allocator&) = default;

    [[nodiscard]] T* allocate(size_t n);
    void deallocate(T* p, size_t n);

    <ins>template&lt;class U&gt;</ins>
    <ins>  friend bool operator==(const allocator&, const allocator&lt;U&gt;&) { return true; }</ins>
  };
}</code></pre></blockquote>

<p>Remove 20.10.10.2 [allocator.globals]:</p>
<blockquote>
<p><pre><code><del>template&lt;class T, class U&gt;
  bool operator==(const allocator&lt;T&gt;&amp;, const allocator&lt;U&gt;&amp;) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">true</code>.</del>
<del><pre><code>template&lt;class T, class U&gt;
  bool operator!=(const allocator&lt;T&gt;&amp;, const allocator&lt;U&gt;&amp;) noexcept;</code></pre></del>
<del><em>Returns</em>: <code class="language-cpp">false</code>.</del></p>
</blockquote>
<p>Change 20.11.1.2 [unique.ptr.single]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class T, class D = default_delete&lt;T&gt;&gt; class unique_ptr {
  public:
    using pointer      = <i>see below</i>;
    using element_type = T;
    using deleter_type = D;
    [...]
    // disable copy from lvalue
    unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;

<ins>    // [unique.ptr.special] Specialized algorithms
    template&lt;class T2, class D2&gt;
      friend bool operator==(const unique_ptr& x, const unique_ptr&lt;T2, D2&gt;& y) { return x.get() == y.get(); }
    template&lt;class T2, class D2&gt;
      friend bool operator&lt;(const unique_ptr& x, const unique_ptr&lt;T2, D2&gt;& y) { <i>see below</i> }
    template&lt;class T2, class D2&gt;
      friend bool operator&gt;(const unique_ptr& x, const unique_ptr&lt;T2, D2&gt;& y) { <i>see below</i> }
    template&lt;class T2, class D2&gt;
      friend bool operator&lt;=(const unique_ptr& x, const unique_ptr&lt;T2, D2&gt;& y) { <i>see below</i> }
    template&lt;class T2, class D2&gt;
      friend bool operator&gt;=(const unique_ptr& x, const unique_ptr&lt;T2, D2&gt;& y) { <i>see below</i> }
    template&lt;class T2, class D2&gt;
        requires ThreeWayComparableWith&lt;pointer, typename unique_ptr&lt;T2, D2&gt;::pointer&gt;
      friend auto operator&lt;=&gt;(const unique_ptr& x, const unique_ptr&lt;T2, D2&gt;& y)
      { return compare_three_way()(x.get(), y.get()); }

    friend bool operator==(const unique_ptr& x, nullptr_t) noexcept { return !x; }
    friend auto operator&lt;=&gt;(const unique_ptr& x, nullptr_t)
      requires ThreeWayComparableWith&lt;pointer, nullptr_t&gt;
      { return compare_three_way()(x.get(), nullptr); }</ins>
  };
}</code></pre></blockquote>

<p>Change 20.11.1.3 [unique.ptr.runtime]:</p>
<blockquote><pre><code>namespace std {
  template<class T, class D> class unique_ptr<T[], D> {
  public:
    [...]
    // disable copy from lvalue
    unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;

<ins>    // [unique.ptr.special] Specialized algorithms
    template&lt;class T2, class D2&gt;
      friend bool operator==(const unique_ptr& x, const unique_ptr&lt;T2, D2&gt;& y) { return x.get() == y.get(); }
    template&lt;class T2, class D2&gt;
      friend bool operator&lt;(const unique_ptr& x, const unique_ptr&lt;T2, D2&gt;& y) { <i>see below</i> }
    template&lt;class T2, class D2&gt;
      friend bool operator&gt;(const unique_ptr& x, const unique_ptr&lt;T2, D2&gt;& y) { <i>see below</i> }
    template&lt;class T2, class D2&gt;
      friend bool operator&lt;=(const unique_ptr& x, const unique_ptr&lt;T2, D2&gt;& y) { <i>see below</i> }
    template&lt;class T2, class D2&gt;
      friend bool operator&gt;=(const unique_ptr& x, const unique_ptr&lt;T2, D2&gt;& y) { <i>see below</i> }
    template&lt;class T2, class D2&gt;
        requires ThreeWayComparableWith&lt;pointer, typename unique_ptr&lt;T2, D2&gt;::pointer&gt;
      friend auto operator&lt;=&gt;(const unique_ptr& x, const unique_ptr&lt;T2, D2&gt;& y)
      { return compare_three_way()(x.get(), y.get()); }

    friend bool operator==(const unique_ptr& x, nullptr_t) noexcept { return !x; }
    friend auto operator&lt;=&gt;(const unique_ptr& x, nullptr_t)
      requires ThreeWayComparableWith&lt;pointer, nullptr_t&gt;
      { return compare_three_way()(x.get(), nullptr); }</ins>  
  };
}</code></pre></blockquote>

<p>Change 20.11.1.5 [unique.ptr.special]:</p>
<blockquote>
<p><pre><code>template&lt;class T, class D&gt; void swap(unique_ptr&lt;T, D&gt;&amp; x, unique_ptr&lt;T, D&gt;&amp; y) noexcept;</code></pre>
<em>Remarks</em>: This function shall not participate in overload resolution unless <code class="language-cpp">is_swappable_v&lt;D&gt;</code> is <code class="language-cpp">true</code>.
<em>Effects</em>: Calls <code class="language-cpp">x.swap(y)</code>.
<pre><code><del>template&lt;class T1, class D1, class T2, class D2&gt;</del>
  <del>bool operator==(const unique_ptr&lt;T1, D1&gt;&amp; x, const unique_ptr&lt;T2, D2&gt;&amp; y);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">x.get() == y.get()</code>.</del>
<pre><code><del>template&lt;class T1, class D1, class T2, class D2&gt;
  bool operator!=(const unique_ptr&lt;T1, D1&gt;&amp; x, const unique_ptr&lt;T2, D2&gt;&amp; y);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">x.get() != y.get()</code>.</del>
<pre><code>template&lt;<del>class T1, class D1, </del>class T2, class D2&gt;
  <ins>friend </ins>bool operator&lt;(const unique_ptr<del>&lt;T1, D1&gt;</del>&amp; x, const unique_ptr&lt;T2, D2&gt;&amp; y);</code></pre>
<em>Requires</em>: Let <code class="language-cpp">CT</code> denote <code>common_type_t&lt;<del>typename unique_ptr&lt;T1, D1&gt;::</del>pointer, typename unique_ptr&lt;T2, D2&gt;::pointer&gt;</code> Then the specialization <code class="language-cpp">less&lt;CT&gt;</code> shall be a function object type that induces a strict weak ordering on the pointer values.<br />
<em>Returns</em>: <code class="language-cpp">less&lt;CT&gt;()(x.get(), y.get())</code>.<br />
<del><em>Remarks</em>: If <code class="language-cpp">unique_ptr&lt;T1, D1&gt;::pointer</code> is not implicitly convertible to <code class="language-cpp">CT</code> or <code class="language-cpp">unique_ptr&lt;T2, D2&gt;::pointer</code> is not implicitly convertible to <code class="language-cpp">CT</code>, the program is ill-formed.</del><br />
<ins><em>Mandates</em>: <code class="language-cpp">pointer</code> and <code class="language-cpp">unique_ptr&lt;T2, D2&gt;::pointer</code> are implicitly convertible to <code class="language-cpp">CT</code>.</ins><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T1, class D1, </del>class T2, class D2&gt;
  <ins>friend </ins>bool operator&gt;(const unique_ptr<del>&lt;T1, D1&gt;</del>&amp; x, const unique_ptr&lt;T2, D2&gt;&amp; y);</code></pre>
<em>Returns</em>: <code class="language-cpp">y &lt; x</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T1, class D1, </del>class T2, class D2&gt;
  <ins>friend </ins>bool operator&lt;=(const unique_ptr<del>&lt;T1, D1&gt;</del>&amp; x, const unique_ptr&lt;T2, D2&gt;&amp; y);</code></pre>
<em>Returns</em>: <code class="language-cpp">!(y &lt; x)</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class T1, class D1, </del>class T2, class D2&gt;
  <ins>friend </ins>bool operator&gt;=(const unique_ptr<del>&lt;T1, D1&gt;</del>&amp; x, const unique_ptr&lt;T2, D2&gt;&amp; y);</code></pre>
<em>Returns</em>: <code class="language-cpp">!(x &lt; y)</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins></p>
</blockquote>
<p>Change 20.11.3, [util.smartptr.shared]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class T&gt; class shared_ptr {
    [...]
    // [util.smartptr.shared.obs], observers
    element_type* get() const noexcept;
    T& operator*() const noexcept;
    T* operator-&gt;() const noexcept;
    element_type& operator[](ptrdiff_t i) const;
    long use_count() const noexcept;
    explicit operator bool() const noexcept;
    template&lt;class U&gt;
      bool owner_before(const shared_ptr&lt;U&gt;& b) const noexcept;
    template&lt;class U&gt;
      bool owner_before(const weak_ptr&lt;U&gt;& b) const noexcept;

    <ins>// [util.smartptr.shared.cmp], shared_ptr comparisons</ins>
    <ins>template&lt;class U&gt;</ins>
      <ins>friend bool operator==(const shared_ptr& a, const shared_ptr&lt;U&gt;& b) noexcept</ins>
      <ins>{ return a.get() == b.get(); }</ins>
    <ins>template&lt;class U&gt;</ins>
      <ins>friend strong_ordering operator&lt;=&gt;(const shared_ptr& a, const shared_ptr&lt;U&gt;& b) noexcept</ins>
      <ins>{ return compare_three_way()(a.get(), b.get()); }</ins>

    <ins>friend bool operator==(const shared_ptr& a, nullptr_t) noexcept { return !a; }</ins>
    <ins>friend strong_ordering operator&lt;=&gt;(const shared_ptr& a, nullptr_t) noexcept</ins>
    <ins>  { return compare_three_way()(a.get(), nullptr); }</ins>
  };
}</code></pre></blockquote>

<p>Remove all of 20.11.3.7 [util.smartptr.shared.cmp]:</p>
<blockquote>
<p><pre><code><del>template&lt;class T, class U&gt;</del>
<del>  bool operator==(const shared_ptr&lt;T&gt;&amp; a, const shared_ptr&lt;U&gt;&amp; b) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">a.get() == b.get()</code>.</del>
<pre><code><del>template&lt;class T, class U&gt;
  bool operator&lt;(const shared_ptr&lt;T&gt;&amp; a, const shared_ptr&lt;U&gt;&amp; b) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">less&lt;&gt;()(a.get(), b.get())</code>.</del><br />
[...]</p>
</blockquote>
<p>Change 20.12.1 [mem.res.syn]:</p>
<blockquote><pre><code>namespace std::pmr {
  // [mem.res.class], class memory_resource
  class memory_resource;

  <del>bool operator==(const memory_resource& a, const memory_resource& b) noexcept;</del>
  <del>bool operator!=(const memory_resource& a, const memory_resource& b) noexcept;</del>

  // [mem.poly.allocator.class], class template polymorphic_allocator
  template&lt;class Tp&gt; class polymorphic_allocator;

  <del>template&lt;class T1, class T2&gt;</del>
  <del>  bool operator==(const polymorphic_allocator&lt;T1&gt;& a,</del>
  <del>                  const polymorphic_allocator&lt;T2&gt;& b) noexcept;</del>
  <del>template&lt;class T1, class T2&gt;</del>
  <del>  bool operator!=(const polymorphic_allocator&lt;T1&gt;& a,</del>
  <del>                  const polymorphic_allocator&lt;T2&gt;& b) noexcept;</del>

  // [mem.res.global], global memory resources
  memory_resource* new_delete_resource() noexcept;
  [...]
}</code></pre></blockquote>

<p>Change 20.12.2 [mem.res.class]:</p>
<blockquote><pre><code>namespace std::pmr {
  class memory_resource {
    static constexpr size_t max_align = alignof(max_align_t);   // exposition only

  public:
    memory_resource() = default;
    memory_resource(const memory_resource&) = default;
    virtual ~memory_resource();

    memory_resource& operator=(const memory_resource&) = default;

    [[nodiscard]] void* allocate(size_t bytes, size_t alignment = max_align);
    void deallocate(void* p, size_t bytes, size_t alignment = max_align);

    bool is_equal(const memory_resource& other) const noexcept;

    <ins>friend bool operator==(const memory_resource&, const memory_resource&) noexcept { <i>see below</i> }</ins>

  private:
    virtual void* do_allocate(size_t bytes, size_t alignment) = 0;
    virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0;

    virtual bool do_is_equal(const memory_resource& other) const noexcept = 0;
  };
}</code></pre></blockquote>

<p>Change 20.12.2.3 [mem.res.eq]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>bool operator==(const memory_resource&amp; a, const memory_resource&amp; b) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">&amp;a == &amp;b || a.is_equal(b)</code>.
<pre><code><del>bool operator!=(const memory_resource&amp; a, const memory_resource&amp; b) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(a == b)</code>.</del></p>
</blockquote>
<p>Change 20.12.3 [mem.poly.allocator.class]:</p>
<blockquote><pre><code>namespace std::pmr {
  template&lt;class Tp&gt; class polymorphic_allocator {
    memory_resource* memory_rsrc;     // exposition only

  public:
    [...]

    memory_resource* resource() const;

    <ins>template&lt;class T2&gt;</ins>
    <ins>  friend bool operator==(const polymorphic_allocator& a, const polymorphic_allocator&lt;T2&gt;& b)</ins>
    <ins>  { <i>see below</i> }</ins>
  };
}</code></pre></blockquote>

<p>Change 20.12.3.3 [mem.poly.allocator.eq]:</p>
<blockquote>
<p><pre><code>template&lt;<del>class T1, </del>class T2&gt;
  <ins>friend </ins>bool operator==(const polymorphic_allocator<del>&lt;T1&gt;</del>&amp; a,
                  const polymorphic_allocator&lt;T2&gt;&amp; b) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">*a.resource() == *b.resource()</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><del>template&lt;class T1, class T2&gt;</del>
<del>  bool operator!=(const polymorphic_allocator&lt;T1&gt;&amp; a,</del>
<del>                  const polymorphic_allocator&lt;T2&gt;&amp; b) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(a == b)</code>.</del></p>
</blockquote>
<p>Change 20.13.1 [allocator.adaptor.syn]:</p>
<blockquote><pre><code>namespace std {
  // class template scoped allocator adaptor
  template&lt;class OuterAlloc, class... InnerAlloc&gt;
    class scoped_allocator_adaptor;

  <del>// [scoped.adaptor.operators], scoped allocator operators</del>
  <del>template&lt;class OuterA1, class OuterA2, class... InnerAllocs&gt;</del>
  <del>  bool operator==(const scoped_allocator_adaptor&lt;OuterA1, InnerAllocs...&gt;& a,</del>
  <del>                  const scoped_allocator_adaptor&lt;OuterA2, InnerAllocs...&gt;& b) noexcept;</del>
  <del>template&lt;class OuterA1, class OuterA2, class... InnerAllocs&gt;</del>
  <del>  bool operator!=(const scoped_allocator_adaptor&lt;OuterA1, InnerAllocs...&gt;& a,</del>
  <del>                  const scoped_allocator_adaptor&lt;OuterA2, InnerAllocs...&gt;& b) noexcept;</del>
}</code></pre></blockquote>

<blockquote><pre><code>namespace std {
  template&lt;class OuterAlloc, class... InnerAllocs&gt;
  class scoped_allocator_adaptor : public OuterAlloc {
    [...]
    scoped_allocator_adaptor select_on_container_copy_construction() const;

<ins>    // [scoped.adaptor.operators], scoped allocator operators
    template&lt;class Outer2&gt;
      friend bool operator==(const scoped_allocator_adaptor& a,
                             const scoped_allocator_adaptor&lt;Outer2, InnerAllocs...&gt;& b) noexcept
      { <i> see below</i> }</ins>
  };

  template&lt;class OuterAlloc, class... InnerAllocs&gt;
    scoped_allocator_adaptor(OuterAlloc, InnerAllocs...)
      -&gt; scoped_allocator_adaptor&lt;OuterAlloc, InnerAllocs...&gt;;
}</code></pre></blockquote>

<p>Change 20.13.5 [scoped.adaptor.operators]:</p>
<blockquote>
<p><pre><code>template&lt;<del>class OuterA1, </del>class OuterA2, class... InnerAllocs&gt;
  <ins>friend </ins>bool operator==(const scoped_allocator_adaptor<del>&lt;OuterA1, InnerAllocs...&gt;</del>&amp; a,
                  const scoped_allocator_adaptor&lt;OuterA2, InnerAllocs...&gt;&amp; b) noexcept;</code></pre>
<em>Returns</em>: If <code class="language-cpp">sizeof...(InnerAllocs)</code> is zero,<br />
<code class="language-cpp">a.outer_allocator() == b.outer_allocator()</code><br />
otherwise<br />
<code class="language-cpp">a.outer_allocator() == b.outer_allocator() &amp;&amp; a.inner_allocator() == b.inner_allocator()</code><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><del>template&lt;class OuterA1, class OuterA2, class... InnerAllocs&gt;</del>
<del>  bool operator!=(const scoped_allocator_adaptor&lt;OuterA1, InnerAllocs...&gt;&amp; a,</del>
<del>                  const scoped_allocator_adaptor&lt;OuterA2, InnerAllocs...&gt;&amp; b) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(a == b)</code>.</del></p>
</blockquote>
<p>Change 20.14.1 [functional.syn]</p>
<blockquote><pre><code>namespace std {
  [...]
  <del>template&lt;class R, class... ArgTypes&gt;</del>
  <del>  bool operator==(const function&lt;R(ArgTypes...)&gt;&, nullptr_t) noexcept;</del>
  <del>template&lt;class R, class... ArgTypes&gt;</del>
  <del>  bool operator==(nullptr_t, const function&lt;R(ArgTypes...)&gt;&) noexcept;</del>
  <del>template&lt;class R, class... ArgTypes&gt;</del>
  <del>  bool operator!=(const function&lt;R(ArgTypes...)&gt;&, nullptr_t) noexcept;</del>
  <del>template&lt;class R, class... ArgTypes&gt;</del>
  <del>  bool operator!=(nullptr_t, const function&lt;R(ArgTypes...)&gt;&) noexcept;</del>

  // [func.search], searchers
  [...]
}</code></pre></blockquote>

<p>Change 20.14.8 [range.cmp]/2 to add <code class="language-cpp">&lt;=&gt;</code>:</p>
<blockquote>
<p>There is an implementation-defined strict total ordering over all pointer values of a given type. This total ordering is consistent with the partial order imposed by the builtin operators <code class="language-cpp">&lt;</code>, <code class="language-cpp">&gt;</code>, <code class="language-cpp">&lt;=</code>, <del>and</del> <code class="language-cpp">&gt;=</code><ins>, and <code class="language-cpp">&lt;=&gt;</code></ins>.</p>
</blockquote>
<p>Change 20.14.16.2 [func.wrap.func]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class&gt; class function; // not defined

  template&lt;class R, class... ArgTypes&gt;
  class function&lt;R(ArgTypes...)&gt; {
  public:
    using result_type = R;
    [...]

    // [func.wrap.func.targ], function target access
    const type_info& target_type() const noexcept;
    template&lt;class T&gt;       T* target() noexcept;
    template&lt;class T&gt; const T* target() const noexcept;

    <ins>friend bool operator==(const function& f, nullptr_t) noexcept { return !f; }</ins>
  };    
  [...]
  <del>// [func.wrap.func.nullptr], Null pointer comparisons</del>
  <del>template&lt;class R, class... ArgTypes&gt;</del>
  <del>  bool operator==(const function&lt;R(ArgTypes...)&gt;&, nullptr_t) noexcept;</del>

  <del>template&lt;class R, class... ArgTypes&gt;</del>
  <del>  bool operator==(nullptr_t, const function&lt;R(ArgTypes...)&gt;&) noexcept;</del>

  <del>template&lt;class R, class... ArgTypes&gt;</del>
  <del>  bool operator!=(const function&lt;R(ArgTypes...)&gt;&, nullptr_t) noexcept;</del>

  <del>template&lt;class R, class... ArgTypes&gt;</del>
  <del>  bool operator!=(nullptr_t, const function&lt;R(ArgTypes...)&gt;&) noexcept;</del>
  [...]
}</code></pre></blockquote>

<p>Remove 20.14.16.2.6 [func.wrap.func.nullptr]:</p>
<blockquote>
<p><pre><code><del>template&lt;class R, class... ArgTypes&gt;</del>
<del>  bool operator==(const function&lt;R(ArgTypes...)&gt;&amp; f, nullptr_t) noexcept;</del>
<del>template&lt;class R, class... ArgTypes&gt;</del>
<del>  bool operator==(nullptr_t, const function&lt;R(ArgTypes...)&gt;&amp; f) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!f</code>.</del>
<pre><code><del>template&lt;class R, class... ArgTypes&gt;</del>
<del>  bool operator!=(const function&lt;R(ArgTypes...)&gt;&amp; f, nullptr_t) noexcept;</del>
<del>template&lt;class R, class... ArgTypes&gt;</del>
<del>  bool operator!=(nullptr_t, const function&lt;R(ArgTypes...)&gt;&amp; f) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">(bool)f</code>.</del></p>
</blockquote>
<p>Add a new row to 20.15.4.3 [meta.unary.prop], the "Type property predicates" table:</p>
<blockquote><table>
<tr><th>Template</th><th>Condition</th><th>Preconditions</th></tr>
<tr><td colspan="3"><center>...</center></td></tr>
<tr><td><pre style="background:transparent;border:0px"><code><ins>template&lt;class T&gt;
struct has_strong_structural_equality;</ins></code></pre></td><td><ins>The type <code>T</code> has strong structural equality ([class.compare.default])</ins>.</td><td><ins><code>T</code> shall be a complete type, <code class="language-cpp">cv void</code>, or an array of unknown bound.</ins></td></tr>
</table></blockquote>

<p>Change 20.17.2 [type.index.overview]. Note that the relational operators on <code class="language-cpp">type_index</code> are based on <code class="language-cpp">type_info::before</code> (effectively <code class="language-cpp">&lt;</code>). <code class="language-cpp">type_info</code> <em>could</em> provide a three-way ordering function, but does not. Since an important motivation for the existence of <code class="language-cpp">type_index</code> is to be used as a key in an associative container, we do not want to pessimize <code class="language-cpp">&lt;</code> - but do want to provide <code class="language-cpp">&lt;=&gt;</code>.</p>
<blockquote><pre><code>namespace std {
  class type_index {
  public:
    type_index(const type_info& rhs) noexcept;
    bool operator==(const type_index& rhs) const noexcept;
    <del>bool operator!=(const type_index& rhs) const noexcept;</del>
    bool operator&lt; (const type_index& rhs) const noexcept;
    bool operator&gt; (const type_index& rhs) const noexcept;
    bool operator&lt;= (const type_index& rhs) const noexcept;
    bool operator&gt;= (const type_index& rhs) const noexcept;
    <ins>strong_ordering operator&lt;=&gt;(const type_index& rhs) const noexcept;</ins>
    size_t hash_code() const noexcept;
    const char* name() const noexcept;

  private:
    const type_info* target;    // exposition only
    // Note that the use of a pointer here, rather than a reference,
    // means that the default copy/move constructor and assignment
    // operators will be provided and work as expected.
  };
}</code></pre></blockquote>

<p>Change 20.17.3 [type.index.members]:</p>
<blockquote>
<p><pre><code>type_index(const type_info&amp; rhs) noexcept;</code></pre>
<em>Effects</em>: Constructs a <code class="language-cpp">type_index</code> object, the equivalent of <code class="language-cpp">target = &amp;rhs</code>.
<pre><code>bool operator==(const type_index&amp; rhs) const noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">*target == *rhs.target</code>.
<pre><code><del>bool operator!=(const type_index&amp; rhs) const noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">*target != *rhs.target</code>.</del>
<pre><code>bool operator&lt;(const type_index&amp; rhs) const noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">target-&gt;before(*rhs.target)</code>.
<pre><code>bool operator&gt;(const type_index&amp; rhs) const noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">rhs.target-&gt;before(*target)</code>.
<pre><code>bool operator&lt;=(const type_index&amp; rhs) const noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">!rhs.target-&gt;before(*target)</code>.
<pre><code>bool operator&gt;=(const type_index&amp; rhs) const noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">!target-&gt;before(*rhs.target)</code>.
<pre><code><ins>strong_ordering operator&lt;=&gt;(const type_index&amp; rhs) const noexcept;</ins></code></pre>
<ins><em>Effects</em>: Equivalent to</ins>
<blockquote class="ins"><pre><code>if (*target == *rhs.target) return strong_ordering::equal;
if (target-&gt;before(*rhs.target)) return strong_ordering::less;
return strong_ordering::greater;</code></pre></blockquote>
<pre><code>size_t hash_code() const noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">target-&gt;hash_code()</code>.
[...]</p>
</blockquote>
<p>Change 20.19.1 [charconv.syn]:</p>
<blockquote><pre><code>namespace std {
  [...]

  // [charconv.to.chars], primitive numerical output conversion
  struct to_chars_result {
    char* ptr;
    errc ec;

    <ins>friend bool operator==(const to_chars_result&, const to_chars_result&) = default;</ins>
  };

  [...]

  // [charconv.from.chars], primitive numerical input conversion
  struct from_chars_result {
    const char* ptr;
    errc ec;

    <ins>friend bool operator==(const from_chars_result&, const from_chars_result&) = default;</ins>
  };

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

<h3 id="clause-21-strings-library">4.6. Clause 21: Strings library<a class="self-link" href="#clause-21-strings-library"></a></h3>
<p>Changing the operators for <code class="language-cpp">basic_string</code> and <code class="language-cpp">basic_string_view</code> and adding extra type alises to the <code class="language-cpp">char_traits</code> specializations provided by the standard.</p>
<p>Change 21.2.3.1 [char.traits.specializations.char]:</p>
<blockquote><pre><code>namespace std {
  template&lt;&gt; struct char_traits&lt;char&gt; {
    using char_type  = char;
    using int_type   = int;
    using off_type   = streamoff;
    using pos_type   = streampos;
    using state_type = mbstate_t;
    <ins>using comparison_category = strong_ordering;</ins>
    [...]
  };
}</code></pre></blockquote>

<p>Change 21.2.3.2 [char.traits.specializations.char8_t]:</p>
<blockquote><pre><code>namespace std {
  template&lt;&gt; struct char_traits&lt;char8_t&gt; {
    using char_type = char8_t;
    using int_type = unsigned int;
    using off_type = streamoff;
    using pos_type = u8streampos;
    using state_type = mbstate_t;
    <ins>using comparison_category = strong_ordering;</ins>
    [...]
  };
}</code></pre></blockquote>

<p>Change 21.2.3.3 [char.traits.specializations.char16_t]:</p>
<blockquote><pre><code>namespace std {
  template&lt;&gt; struct char_traits&lt;char16_t&gt; {
    using char_type  = char16_t;
    using int_type   = uint_least16_t;
    using off_type   = streamoff;
    using pos_type   = u16streampos;
    using state_type = mbstate_t;
    <ins>using comparison_category = strong_ordering;</ins>
    [...]
  };
}</code></pre></blockquote>

<p>Change 21.2.3.4 [char.traits.specializations.char32_t]</p>
<blockquote><pre><code>namespace std {
  template&lt;&gt; struct char_traits&lt;char32_t&gt; {
    using char_type  = char32_t;
    using int_type   = uint_least32_t;
    using off_type   = streamoff;
    using pos_type   = u32streampos;
    using state_type = mbstate_t;
    <ins>using comparison_category = strong_ordering;</ins>
    [...]
  };
}</code></pre></blockquote>

<p>Change 21.2.3.5 [char.traits.specializations.wchar.t]</p>
<blockquote><pre><code>namespace std {
  template&lt;&gt; struct char_traits&lt;wchar_t&gt; {
    using char_type  = wchar_t;
    using int_type   = wint_t;
    using off_type   = streamoff;
    using pos_type   = wstreampos;
    using state_type = mbstate_t;
    <ins>using comparison_category = strong_ordering;</ins>
    [...]
  };
}</code></pre></blockquote>

<p>Change 21.3.1 [string.syn]:</p>
<blockquote><pre><code>#include &lt;initializer_list&gt;

namespace std {
  [...]
<del>  template&lt;class charT, class traits, class Allocator&gt;
    bool operator==(const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                    const basic_string&lt;charT, traits, Allocator&gt;& rhs) noexcept;
  template&lt;class charT, class traits, class Allocator&gt;
    bool operator==(const charT* lhs,
                    const basic_string&lt;charT, traits, Allocator&gt;& rhs);
  template&lt;class charT, class traits, class Allocator&gt;
    bool operator==(const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                    const charT* rhs);
  template&lt;class charT, class traits, class Allocator&gt;
    bool operator!=(const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                    const basic_string&lt;charT, traits, Allocator&gt;& rhs) noexcept;
  template&lt;class charT, class traits, class Allocator&gt;
    bool operator!=(const charT* lhs,
                    const basic_string&lt;charT, traits, Allocator&gt;& rhs);
  template&lt;class charT, class traits, class Allocator&gt;
    bool operator!=(const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                    const charT* rhs);

  template&lt;class charT, class traits, class Allocator&gt;
    bool operator&lt; (const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                    const basic_string&lt;charT, traits, Allocator&gt;& rhs) noexcept;
  template&lt;class charT, class traits, class Allocator&gt;
    bool operator&lt; (const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                    const charT* rhs);
  template&lt;class charT, class traits, class Allocator&gt;
    bool operator&lt; (const charT* lhs,
                    const basic_string&lt;charT, traits, Allocator&gt;& rhs);
  template&lt;class charT, class traits, class Allocator&gt;
    bool operator&gt; (const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                    const basic_string&lt;charT, traits, Allocator&gt;& rhs) noexcept;
  template&lt;class charT, class traits, class Allocator&gt;
    bool operator&gt; (const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                    const charT* rhs);
  template&lt;class charT, class traits, class Allocator&gt;
    bool operator&gt; (const charT* lhs,
                    const basic_string&lt;charT, traits, Allocator&gt;& rhs);

  template&lt;class charT, class traits, class Allocator&gt;
    bool operator&lt;=(const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                    const basic_string&lt;charT, traits, Allocator&gt;& rhs) noexcept;
  template&lt;class charT, class traits, class Allocator&gt;
    bool operator&lt;=(const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                    const charT* rhs);
  template&lt;class charT, class traits, class Allocator&gt;
    bool operator&lt;=(const charT* lhs,
                    const basic_string&lt;charT, traits, Allocator&gt;& rhs);
  template&lt;class charT, class traits, class Allocator&gt;
    bool operator&gt;=(const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                    const basic_string&lt;charT, traits, Allocator&gt;& rhs) noexcept;
  template&lt;class charT, class traits, class Allocator&gt;
    bool operator&gt;=(const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                    const charT* rhs);
  template&lt;class charT, class traits, class Allocator&gt;
    bool operator&gt;=(const charT* lhs,
                    const basic_string&lt;charT, traits, Allocator&gt;& rhs);</del>
  [...]
}</code></pre></blockquote>

<p>Change 21.3.2 [basic.string]/3. Insert wherever the editor deems appropriate:</p>
<blockquote><pre><code>namespace std {
  template&lt;class charT, class traits = char_traits&lt;charT&gt;,
           class Allocator = allocator&lt;charT&gt;&gt;
  class basic_string {
    [...]
    <ins>friend bool operator==(const basic_string& lhs, const basic_string& rhs) { <i>see below</i> }</ins>
    <ins>friend bool operator==(const basic_string& lhs, const charT* rhs) { <i>see below</i> }</ins>
    <ins>friend <i>see below</i> operator&lt;=&gt;(const basic_string& lhs, const basic_string& rhs) { <i>see below</i> }</ins>
    <ins>friend <i>see below</i> operator&lt;=&gt;(const basic_string& lhs, const charT* rhs) { <i>see below</i> }</ins>
    [...]
  };
}</code></pre></blockquote>

<p>Change 21.3.3.2 [string.cmp].</p>
<blockquote><pre><code><del>template&lt;class charT, class traits, class Allocator&gt;
  bool operator==(const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                  const basic_string&lt;charT, traits, Allocator&gt;& rhs) noexcept;
template&lt;class charT, class traits, class Allocator&gt;
  bool operator==(const charT* lhs, const basic_string&lt;charT, traits, Allocator&gt;& rhs);
template&lt;class charT, class traits, class Allocator&gt;
  bool operator==(const basic_string&lt;charT, traits, Allocator&gt;& lhs, const charT* rhs);</del>

<ins>friend bool operator==(const basic_string& lhs, const basic_string& rhs);</ins>
<ins>friend bool operator==(const basic_string& lhs, const charT* rhs);</ins>

<del>template&lt;class charT, class traits, class Allocator&gt;
  bool operator!=(const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                  const basic_string&lt;charT, traits, Allocator&gt;& rhs) noexcept;
template&lt;class charT, class traits, class Allocator&gt;
  bool operator!=(const charT* lhs, const basic_string&lt;charT, traits, Allocator&gt;& rhs);
template&lt;class charT, class traits, class Allocator&gt;
  bool operator!=(const basic_string&lt;charT, traits, Allocator&gt;& lhs, const charT* rhs);</code></pre></blockquote>

<blockquote>
<p><ins><em>Effects</em>: Equivalent to <code class="language-cpp">return basic_string_view&lt;charT, traits&gt;(lhs) == basic_string_view&lt;charT, traits&gt;(rhs);</code></ins><br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins></p>
</blockquote>
<blockquote><pre><code><del>template&lt;class charT, class traits, class Allocator&gt;
  bool operator&lt; (const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                  const basic_string&lt;charT, traits, Allocator&gt;& rhs) noexcept;
template&lt;class charT, class traits, class Allocator&gt;
  bool operator&lt; (const charT* lhs, const basic_string&lt;charT, traits, Allocator&gt;& rhs);
template&lt;class charT, class traits, class Allocator&gt;
  bool operator&lt; (const basic_string&lt;charT, traits, Allocator&gt;& lhs, const charT* rhs);

template&lt;class charT, class traits, class Allocator&gt;
  bool operator&gt; (const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                  const basic_string&lt;charT, traits, Allocator&gt;& rhs) noexcept;
template&lt;class charT, class traits, class Allocator&gt;
  bool operator&gt; (const charT* lhs, const basic_string&lt;charT, traits, Allocator&gt;& rhs);
template&lt;class charT, class traits, class Allocator&gt;
  bool operator&gt; (const basic_string&lt;charT, traits, Allocator&gt;& lhs, const charT* rhs);

template&lt;class charT, class traits, class Allocator&gt;
  bool operator&lt;=(const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                  const basic_string&lt;charT, traits, Allocator&gt;& rhs) noexcept;
template&lt;class charT, class traits, class Allocator&gt;
  bool operator&lt;=(const charT* lhs, const basic_string&lt;charT, traits, Allocator&gt;& rhs);
template&lt;class charT, class traits, class Allocator&gt;
  bool operator&lt;=(const basic_string&lt;charT, traits, Allocator&gt;& lhs, const charT* rhs);

template&lt;class charT, class traits, class Allocator&gt;
  bool operator&gt;=(const basic_string&lt;charT, traits, Allocator&gt;& lhs,
                  const basic_string&lt;charT, traits, Allocator&gt;& rhs) noexcept;
template&lt;class charT, class traits, class Allocator&gt;
  bool operator&gt;=(const charT* lhs, const basic_string&lt;charT, traits, Allocator&gt;& rhs);
template&lt;class charT, class traits, class Allocator&gt;
  bool operator&gt;=(const basic_string&lt;charT, traits, Allocator&gt;& lhs, const charT* rhs);</del>

<ins>friend <i>see below</i> operator&lt;=&gt;(const basic_string& lhs, const basic_string& rhs);</ins>  
<ins>friend <i>see below</i> operator&lt;=&gt;(const basic_string& lhs, const charT* rhs);</ins>  
</code></pre></blockquote>

<blockquote>
<p><em>Effects</em>: <del>Let <code class="language-cpp">op</code> be the operator</del>. Equivalent to:
  <pre><code>return basic_string_view&lt;charT, traits&gt;(lhs) <del>op</del> <ins>&lt;=&gt;</ins> basic_string_view&lt;charT, traits&gt;(rhs);</code></pre>
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins></p>
</blockquote>
<p>Change 21.4.1 [string.view.synop]:</p>
<blockquote><pre><code>namespace std {
  // [string.view.template], class template basic_string_view
  template&lt;class charT, class traits = char_traits&lt;charT&gt;&gt;
  class basic_string_view;

  // [string.view.comparison], non-member comparison functions
  <del>template&lt;class charT, class traits&gt;</del>
  <del>  constexpr bool operator==(basic_string_view&lt;charT, traits&gt; x,</del>
  <del>                            basic_string_view&lt;charT, traits&gt; y) noexcept;</del>
  <del>template&lt;class charT, class traits&gt;</del>
  <del>  constexpr bool operator!=(basic_string_view&lt;charT, traits&gt; x,</del>
  <del>                            basic_string_view&lt;charT, traits&gt; y) noexcept;</del>
  <del>template&lt;class charT, class traits&gt;</del>
  <del>  constexpr bool operator&lt; (basic_string_view&lt;charT, traits&gt; x,</del>
  <del>                            basic_string_view&lt;charT, traits&gt; y) noexcept;</del>
  <del>template&lt;class charT, class traits&gt;</del>
  <del>  constexpr bool operator&gt; (basic_string_view&lt;charT, traits&gt; x,</del>
  <del>                            basic_string_view&lt;charT, traits&gt; y) noexcept;</del>
  <del>template&lt;class charT, class traits&gt;</del>
  <del>  constexpr bool operator&lt;=(basic_string_view&lt;charT, traits&gt; x,</del>
  <del>                            basic_string_view&lt;charT, traits&gt; y) noexcept;</del>
  <del>template&lt;class charT, class traits&gt;</del>
  <del>  constexpr bool operator&gt;=(basic_string_view&lt;charT, traits&gt; x,</del>
  <del>                            basic_string_view&lt;charT, traits&gt; y) noexcept;</del>
  <del>// see [string.view.comparison], sufficient additional overloads of comparison functions</del>
  [...]
}</code></pre></blockquote>

<p>Change 21.4.2 [string.view.template], insert wherever the editor deems appropriate</p>
<blockquote><pre><code>template&lt;class charT, class traits = char_traits&lt;charT&gt;&gt;
class basic_string_view {
  [...]
  <ins>friend constexpr bool operator==(basic_string_view, basic_string_view) noexcept { <i>see below</i> }</ins>
  <ins>friend constexpr <i>see below</i> operator&lt;=&gt;(basic_string_view, basic_string_view) noexcept { <i>see below</i> }</ins>
  [...]
};</code></pre></blockquote>

<p>Remove the entirety of 21.4.3 [string.view.comparison]. The proposed two hidden friend declarations satisfy the requirements without needing extra wording. Replace it with the following:</p>
<blockquote>
<p><pre><code>friend constexpr bool operator==(basic_string_view lhs, basic_string_view rhs) noexcept;</code></pre>
<em>Returns:</em> <code class="language-cpp">lhs.compare(rhs) == 0</code>.<br />
<em>Remarks</em>: This function is to be found via argument-dependent lookup only.
<pre><code>friend constexpr <i>see below</i> operator&lt;=&gt;(basic_string_view, basic_string_view) noexcept;</code></pre>
Let <code class="language-cpp">R</code> denote the type <code class="language-cpp">traits::comparison_category</code> if it exists, otherwise <code class="language-cpp">R</code> is <code class="language-cpp">weak_ordering</code>.<br />
<em>Returns:</em> <code class="language-cpp">static_cast&lt;R&gt;(lhs.compare(rhs) &lt;=&gt; 0)</code>.<br />
<em>Remarks</em>: This function is to be found via argument-dependent lookup only.</p>
</blockquote>
<h3 id="clause-22-containers-library">4.7. Clause 22: Containers library<a class="self-link" href="#clause-22-containers-library"></a></h3>
<p>Change 22.3.2 [array.syn]:</p>
<blockquote><pre><code>#include &lt;initializer_list&gt;

namespace std {
  // [array], class template array
  template&lt;class T, size_t N&gt; struct array;

<del>  template&lt;class T, size_t N&gt;
    constexpr bool operator==(const array&lt;T, N&gt;& x, const array&lt;T, N&gt;& y);
  template&lt;class T, size_t N&gt;
    constexpr bool operator!=(const array&lt;T, N&gt;& x, const array&lt;T, N&gt;& y);
  template&lt;class T, size_t N&gt;
    constexpr bool operator&lt; (const array&lt;T, N&gt;& x, const array&lt;T, N&gt;& y);
  template&lt;class T, size_t N&gt;
    constexpr bool operator&gt; (const array&lt;T, N&gt;& x, const array&lt;T, N&gt;& y);
  template&lt;class T, size_t N&gt;
    constexpr bool operator&lt;=(const array&lt;T, N&gt;& x, const array&lt;T, N&gt;& y);
  template&lt;class T, size_t N&gt;
    constexpr bool operator&gt;=(const array&lt;T, N&gt;& x, const array&lt;T, N&gt;& y);</del>
  template&lt;class T, size_t N&gt;
    constexpr void swap(array&lt;T, N&gt;& x, array&lt;T, N&gt;& y) noexcept(noexcept(x.swap(y)));
  [...]
}</code></pre></blockquote>

<p>Change 22.3.3 [deque.syn]:</p>
<blockquote><pre><code>#include &lt;initializer_list&gt;

namespace std {
  // [deque], class template deque
  template&lt;class T, class Allocator = allocator&lt;T&gt;&gt; class deque;

<del>  template&lt;class T, class Allocator&gt;
    bool operator==(const deque&lt;T, Allocator&gt;& x, const deque&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator!=(const deque&lt;T, Allocator&gt;& x, const deque&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&lt; (const deque&lt;T, Allocator&gt;& x, const deque&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&gt; (const deque&lt;T, Allocator&gt;& x, const deque&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&lt;=(const deque&lt;T, Allocator&gt;& x, const deque&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&gt;=(const deque&lt;T, Allocator&gt;& x, const deque&lt;T, Allocator&gt;& y);</del>

  template&lt;class T, class Allocator&gt;
    void swap(deque&lt;T, Allocator&gt;& x, deque&lt;T, Allocator&gt;& y)
      noexcept(noexcept(x.swap(y)));

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

<p>Change 22.3.4 [forward_list.syn]:</p>
<blockquote><pre><code>#include &lt;initializer_list&gt;

namespace std {
  // [forwardlist], class template forwardlist
  template&lt;class T, class Allocator = allocator&lt;T&gt;&gt; class forward_list;

<del>  template&lt;class T, class Allocator&gt;
    bool operator==(const forward_list&lt;T, Allocator&gt;& x, const forward_list&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator!=(const forward_list&lt;T, Allocator&gt;& x, const forward_list&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&lt; (const forward_list&lt;T, Allocator&gt;& x, const forward_list&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&gt; (const forward_list&lt;T, Allocator&gt;& x, const forward_list&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&lt;=(const forward_list&lt;T, Allocator&gt;& x, const forward_list&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&gt;=(const forward_list&lt;T, Allocator&gt;& x, const forward_list&lt;T, Allocator&gt;& y);</del>

  template&lt;class T, class Allocator&gt;
    void swap(forward_list&lt;T, Allocator&gt;& x, forward_list&lt;T, Allocator&gt;& y)
      noexcept(noexcept(x.swap(y)));

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

<p>Change 22.3.5 [list.syn]:</p>
<blockquote><pre><code>#include &lt;initializer_list&gt;

namespace std {
  // [list], class template list
  template&lt;class T, class Allocator = allocator&lt;T&gt;&gt; class list;

<del>  template&lt;class T, class Allocator&gt;
    bool operator==(const list&lt;T, Allocator&gt;& x, const list&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator!=(const list&lt;T, Allocator&gt;& x, const list&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&lt; (const list&lt;T, Allocator&gt;& x, const list&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&gt; (const list&lt;T, Allocator&gt;& x, const list&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&lt;=(const list&lt;T, Allocator&gt;& x, const list&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&gt;=(const list&lt;T, Allocator&gt;& x, const list&lt;T, Allocator&gt;& y);</del>

  template&lt;class T, class Allocator&gt;
    void swap(list&lt;T, Allocator&gt;& x, list&lt;T, Allocator&gt;& y)
      noexcept(noexcept(x.swap(y)));

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

<p>Change 22.3.6 [vector.syn]:</p>
<blockquote><pre><code>#include &lt;initializer_list&gt;

namespace std {
  // [vector], class template vector
  template&lt;class T, class Allocator = allocator&lt;T&gt;&gt; class vector;

<del>  template&lt;class T, class Allocator&gt;
    bool operator==(const vector&lt;T, Allocator&gt;& x, const vector&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator!=(const vector&lt;T, Allocator&gt;& x, const vector&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&lt; (const vector&lt;T, Allocator&gt;& x, const vector&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&gt; (const vector&lt;T, Allocator&gt;& x, const vector&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&lt;=(const vector&lt;T, Allocator&gt;& x, const vector&lt;T, Allocator&gt;& y);
  template&lt;class T, class Allocator&gt;
    bool operator&gt;=(const vector&lt;T, Allocator&gt;& x, const vector&lt;T, Allocator&gt;& y);</del>

  template&lt;class T, class Allocator&gt;
    void swap(vector&lt;T, Allocator&gt;& x, vector&lt;T, Allocator&gt;& y)
      noexcept(noexcept(x.swap(y)));

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

<p>Add to 22.2.1 [container.requirements.general], paragraph 4:</p>
<blockquote>
<p>In Tables 62, 63, and 64 <code class="language-cpp">X</code> denotes a container class containing objects of type <code class="language-cpp">T</code>, <code class="language-cpp">a</code> and <code class="language-cpp">b</code> denote values of type <code class="language-cpp">X</code>, <ins><code class="language-cpp">i</code> and <code class="language-cpp">j</code> denote values of type (possibly-const) <code class="language-cpp">X::iterator</code>,</ins> <code class="language-cpp">u</code> denotes an identifier, <code class="language-cpp">r</code> denotes a non-const value of type <code class="language-cpp">X</code>, and <code class="language-cpp">rv</code> denotes a non-const rvalue of type <code class="language-cpp">X</code>.</p>
</blockquote>
<p>Add a row to Table 62 — Container requirements:</p>
<blockquote><table>
<tr><th>Expression</th><th>Return<br/>type</th><th>Operational<br/>semantics</th><th>Assertion/note<br />pre/post-condition</th><th>Complexity</th></tr>
<tr><td><pre><code><ins>i &lt;=&gt; j</ins></code></pre></td><td><ins><code>strong_ordering</code> if <code>X::iterator</code> meets the random access iterator requirements, otherwise <code>strong_equality</code></ins></td><td></td><td></td><td><ins>constant</ins></td></tr>
</table></blockquote>

<p>Add to 22.2.1 [container.requirements.general], paragraph 7:</p>
<blockquote>
<p>In the expressions
<pre><code>i == j
i != j
i &lt; j
i &lt;= j
i &gt;= j
i &gt; j
<ins>i &lt;=&gt; j</ins>
i - j</code></pre>
where <code class="language-cpp">i</code> and <code class="language-cpp">j</code> denote objects of a container's <code class="language-cpp">iterator</code> type, either or both may be replaced by an object of the container's <code class="language-cpp">const_iterator</code> type referring to the same element with no change in semantics.</p>
</blockquote>
<p>Remove 22.2.1 [container.requirements.general] table 64 - the optional container operations are now just <code class="language-cpp">&lt;=&gt;</code> instead of the four relational operators, and will be defined inline following the LWG guidance for <code class="language-cpp">flat_map</code>.</p>
<blockquote><del>Table 64 lists operations that are provided for some types of containers but not others. Those containers for which the listed operations are provided shall implement the semantics described in Table 64 unless otherwise stated. If the iterators passed to <code>lexicographical_compare</code> satisfy the constexpr iterator requirements ([iterator.requirements.general]) then the operations described in Table 64 are implemented by constexpr functions.</del>

<table>
<tr><th><del>Expression</del></th><th><del>Return<br/>type</del></th><th><del>Operational<br/>semantics</del></th><th><Del>Assertion/note<br />pre/post-condition</del></th><th><del>Complexity</del></th></tr>
<tr><td><pre><code><del>a &lt; b</del></code></pre></td><td><del>convertible to <code>bool</code></del></td><td><pre><code><del>lexicographical_compare(
  a.begin(), a.end(),
  b.begin(), b.end())</del></code></pre></td><td><del><i>Requires</i>: <code>&lt;</code> is defined for values of <code>T</code>. <code>&lt;</code> is a total ordering relationship.</del></td><td><del>linear</del></td></tr>
<tr><td><pre><code><del>a &gt; b</del></code></pre></td><td><del>convertible to <code>bool</code></del><td><pre><code><del>b &lt; a</del></code></pre></td><td></td><td><del>linear</del></td></tr>
<tr><td><pre><code><del>a &lt;= b</del></code></pre></td><td><del>convertible to <code>bool</code></del><td><pre><code><del>!(a &gt; b)</del></code></pre></td><td></td><td><del>linear</del></td></tr>
<tr><td><pre><code><del>a &gt;= b</del></code></pre></td><td><del>convertible to <code>bool</code></del><td><pre><code><del>!(a &lt; b)</del></code></pre></td><td></td><td><del>linear</del></td></tr>
</table>

<Del>[<i>Note</i>: The algorithm <code>lexicographical_compare()</code> is defined in [algorithms]. —<i>end note</i>]</del>

</blockquote>

<p>Change 22.3.7.1, paragraph 4 [array.overview]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class T, size_t N&gt;
  struct array {
    [...]

    constexpr T *       data() noexcept;
    constexpr const T * data() const noexcept;

    <ins>friend constexpr bool operator==(const array&, const array&) = default;</ins>
    <ins>friend constexpr <i>synth-3way-result</i>&lt;value_type&gt; operator&lt;=&gt;(const array& x, const array& y)</ins>
    <ins>  { return lexicographical_compare_three_way(x.begin(), x.end(), y.begin(), y.end(), <i>synth-3way</i>); }</ins>
  };

  template&lt;class T, class... U&gt;
    array(T, U...) -&gt; array&lt;T, 1 + sizeof...(U)&gt;;
}</code></pre></blockquote>

<p>Change 22.3.8.1, paragraph 2 [deque.overview]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class T, class Allocator = allocator&lt;T&gt;&gt;
  class deque {
  public:
    [...]
    void     swap(deque&)
      noexcept(allocator_traits&lt;Allocator&gt;::is_always_equal::value);
    void     clear() noexcept;

    <ins>friend bool operator==(const deque& x, const deque& y)</ins>
    <ins>  { return ranges::equal(x, y); }</ins>
    <ins>friend <i>synth-3way-result</i>&lt;value_type&gt; operator&lt;=&gt;(const deque& x, const deque& y)</ins>
    <ins>  { return lexicographical_compare_three_way(x.begin(), x.end(), y.begin(), y.end(), <i>synth-3way</i>); }</ins>
  };

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

<p>Change 22.3.9.1, paragraph 3 [forwardlist.overview]</p>
<blockquote><pre><code>namespace std {
  template&lt;class T, class Allocator = allocator&lt;T&gt;&gt;
  class forward_list {
  public:
    [...]
    void sort();
    template&lt;class Compare&gt; void sort(Compare comp);

    void reverse() noexcept;

    <ins>friend bool operator==(const forward_list& x, const forward_list& y)</ins>
    <ins>  { return ranges::equal(x, y); }</ins>
    <ins>friend <i>synth-3way-result</i>&lt;value_type&gt; operator&lt;=&gt;(const forward_list& x, const forward_list& y)</ins>
    <ins>  { return lexicographical_compare_three_way(x.begin(), x.end(), y.begin(), y.end(), <i>synth-3way</i>); }</ins>
  };

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

<p>Change 22.3.10.1, paragraph 2 [list.overview]</p>
<blockquote><pre><code>namespace std {
  template&lt;class T, class Allocator = allocator&lt;T&gt;&gt;
  class list {
  public:
    [...]
    void sort();
    template&lt;class Compare&gt; void sort(Compare comp);

    void reverse() noexcept;

    <ins>friend bool operator==(const list& x, const list& y)</ins>
    <ins>  { return ranges::equal(x, y); }</ins>
    <ins>friend <i>synth-3way-result</i>&lt;value_type&gt; operator&lt;=&gt;(const list& x, const list& y)</ins>
    <ins>  { return lexicographical_compare_three_way(x.begin(), x.end(), y.begin(), y.end(), <i>synth-3way</i>); }</ins>
  };

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

<p>Change 22.3.11.1, paragraph 2 [vector.overview]</p>
<blockquote><pre><code>namespace std {
  template&lt;class T, class Allocator = allocator&lt;T&gt;&gt;
  class vector {
  public:
    [...]
    void     swap(vector&)
      noexcept(allocator_traits&lt;Allocator&gt;::propagate_on_container_swap::value ||
               allocator_traits&lt;Allocator&gt;::is_always_equal::value);
    void     clear() noexcept;

    <ins>friend bool operator==(const vector& x, const vector& y)</ins>
    <ins>  { return ranges::equal(x, y); }</ins>
    <ins>friend <i>synth-3way-result</i>&lt;value_type&gt; operator&lt;=&gt;(const vector& x, const vector& y)</ins>
    <ins>  { return lexicographical_compare_three_way(x.begin(), x.end(), y.begin(), y.end(), <i>synth-3way</i>); }</ins>   
  };
  [...]
}</code></pre></blockquote>

<p>Change 22.3.12 [vector.bool]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class Allocator&gt;
  class vector&lt;bool, Allocator&gt; {
  public:
    [...]
    static void swap(reference x, reference y) noexcept;
    void flip() noexcept;       // flips all bits
    void clear() noexcept;

    <ins>friend bool operator==(const vector& x, const vector& y)</ins>
    <ins>  { return ranges::equal(x, y); }</ins>
    <ins>friend strong_ordering operator&lt;=&gt;(const vector& x, const vector& y)</ins>
    <ins>  { return lexicographical_compare_three_way(x.begin(), x.end(), y.begin(), y.end(), compare_three_way()); }</ins>
  };
}</code></pre></blockquote>

<p>Change 22.4.2 [associative.map.syn]:</p>
<blockquote><pre><code>#include &lt;initializer_list&gt;

namespace std {
  // [map], class template map
  template&lt;class Key, class T, class Compare = less&lt;Key&gt;,
           class Allocator = allocator&lt;pair&lt;const Key, T&gt;&gt;&gt;
    class map;

<del>  template&lt;class Key, class T, class Compare, class Allocator&gt;
    bool operator==(const map&lt;Key, T, Compare, Allocator&gt;& x,
                    const map&lt;Key, T, Compare, Allocator&gt;& y);
  template&lt;class Key, class T, class Compare, class Allocator&gt;
    bool operator!=(const map&lt;Key, T, Compare, Allocator&gt;& x,
                    const map&lt;Key, T, Compare, Allocator&gt;& y);
  template&lt;class Key, class T, class Compare, class Allocator&gt;
    bool operator&lt; (const map&lt;Key, T, Compare, Allocator&gt;& x,
                    const map&lt;Key, T, Compare, Allocator&gt;& y);
  template&lt;class Key, class T, class Compare, class Allocator&gt;
    bool operator&gt; (const map&lt;Key, T, Compare, Allocator&gt;& x,
                    const map&lt;Key, T, Compare, Allocator&gt;& y);
  template&lt;class Key, class T, class Compare, class Allocator&gt;
    bool operator&lt;=(const map&lt;Key, T, Compare, Allocator&gt;& x,
                    const map&lt;Key, T, Compare, Allocator&gt;& y);
  template&lt;class Key, class T, class Compare, class Allocator&gt;
    bool operator&gt;=(const map&lt;Key, T, Compare, Allocator&gt;& x,
                    const map&lt;Key, T, Compare, Allocator&gt;& y);</del>

  template&lt;class Key, class T, class Compare, class Allocator&gt;
    void swap(map&lt;Key, T, Compare, Allocator&gt;& x,
              map&lt;Key, T, Compare, Allocator&gt;& y)
      noexcept(noexcept(x.swap(y)));

  template &lt;class Key, class T, class Compare, class Allocator, class Predicate&gt;
    void erase_if(map&lt;Key, T, Compare, Allocator&gt;& c, Predicate pred);

  // [multimap], class template multimap
  template&lt;class Key, class T, class Compare = less&lt;Key&gt;,
           class Allocator = allocator&lt;pair&lt;const Key, T&gt;&gt;&gt;
    class multimap;

<del>  template&lt;class Key, class T, class Compare, class Allocator&gt;
    bool operator==(const multimap&lt;Key, T, Compare, Allocator&gt;& x,
                    const multimap&lt;Key, T, Compare, Allocator&gt;& y);
  template&lt;class Key, class T, class Compare, class Allocator&gt;
    bool operator!=(const multimap&lt;Key, T, Compare, Allocator&gt;& x,
                    const multimap&lt;Key, T, Compare, Allocator&gt;& y);
  template&lt;class Key, class T, class Compare, class Allocator&gt;
    bool operator&lt; (const multimap&lt;Key, T, Compare, Allocator&gt;& x,
                    const multimap&lt;Key, T, Compare, Allocator&gt;& y);
  template&lt;class Key, class T, class Compare, class Allocator&gt;
    bool operator&gt; (const multimap&lt;Key, T, Compare, Allocator&gt;& x,
                    const multimap&lt;Key, T, Compare, Allocator&gt;& y);
  template&lt;class Key, class T, class Compare, class Allocator&gt;
    bool operator&lt;=(const multimap&lt;Key, T, Compare, Allocator&gt;& x,
                    const multimap&lt;Key, T, Compare, Allocator&gt;& y);
  template&lt;class Key, class T, class Compare, class Allocator&gt;
    bool operator&gt;=(const multimap&lt;Key, T, Compare, Allocator&gt;& x,
                    const multimap&lt;Key, T, Compare, Allocator&gt;& y);</del>

  template&lt;class Key, class T, class Compare, class Allocator&gt;
    void swap(multimap&lt;Key, T, Compare, Allocator&gt;& x,
              multimap&lt;Key, T, Compare, Allocator&gt;& y)
      noexcept(noexcept(x.swap(y)));

  template &lt;class Key, class T, class Compare, class Allocator, class Predicate&gt;
    void erase_if(multimap&lt;Key, T, Compare, Allocator&gt;& c, Predicate pred);

  namespace pmr {
    template&lt;class Key, class T, class Compare = less&lt;Key&gt;&gt;
      using map = std::map&lt;Key, T, Compare,
                           polymorphic_allocator&lt;pair&lt;const Key, T&gt;&gt;&gt;;

    template&lt;class Key, class T, class Compare = less&lt;Key&gt;&gt;
      using multimap = std::multimap&lt;Key, T, Compare,
                                     polymorphic_allocator&lt;pair&lt;const Key, T&gt;&gt;&gt;;
  }
}</code></pre></blockquote>

<p>Change 22.4.3 [associative.set.syn]:</p>
<blockquote><pre><code>#include &lt;initializer_list&gt;

namespace std {
  // [set], class template set
  template&lt;class Key, class Compare = less&lt;Key&gt;, class Allocator = allocator&lt;Key&gt;&gt;
    class set;

<del>  template&lt;class Key, class Compare, class Allocator&gt;
    bool operator==(const set&lt;Key, Compare, Allocator&gt;& x,
                    const set&lt;Key, Compare, Allocator&gt;& y);
  template&lt;class Key, class Compare, class Allocator&gt;
    bool operator!=(const set&lt;Key, Compare, Allocator&gt;& x,
                    const set&lt;Key, Compare, Allocator&gt;& y);
  template&lt;class Key, class Compare, class Allocator&gt;
    bool operator&lt; (const set&lt;Key, Compare, Allocator&gt;& x,
                    const set&lt;Key, Compare, Allocator&gt;& y);
  template&lt;class Key, class Compare, class Allocator&gt;
    bool operator&gt; (const set&lt;Key, Compare, Allocator&gt;& x,
                    const set&lt;Key, Compare, Allocator&gt;& y);
  template&lt;class Key, class Compare, class Allocator&gt;
    bool operator&lt;=(const set&lt;Key, Compare, Allocator&gt;& x,
                    const set&lt;Key, Compare, Allocator&gt;& y);
  template&lt;class Key, class Compare, class Allocator&gt;
    bool operator&gt;=(const set&lt;Key, Compare, Allocator&gt;& x,
                    const set&lt;Key, Compare, Allocator&gt;& y);</del>

  template&lt;class Key, class Compare, class Allocator&gt;
    void swap(set&lt;Key, Compare, Allocator&gt;& x,
              set&lt;Key, Compare, Allocator&gt;& y)
      noexcept(noexcept(x.swap(y)));

  template &lt;class Key, class Compare, class Allocator, class Predicate&gt;
    void erase_if(set&lt;Key, Compare, Allocator&gt;& c, Predicate pred);

  // [multiset], class template multiset
  template&lt;class Key, class Compare = less&lt;Key&gt;, class Allocator = allocator&lt;Key&gt;&gt;
    class multiset;

<del>  template&lt;class Key, class Compare, class Allocator&gt;
    bool operator==(const multiset&lt;Key, Compare, Allocator&gt;& x,
                    const multiset&lt;Key, Compare, Allocator&gt;& y);
  template&lt;class Key, class Compare, class Allocator&gt;
    bool operator!=(const multiset&lt;Key, Compare, Allocator&gt;& x,
                    const multiset&lt;Key, Compare, Allocator&gt;& y);
  template&lt;class Key, class Compare, class Allocator&gt;
    bool operator&lt; (const multiset&lt;Key, Compare, Allocator&gt;& x,
                    const multiset&lt;Key, Compare, Allocator&gt;& y);
  template&lt;class Key, class Compare, class Allocator&gt;
    bool operator&gt; (const multiset&lt;Key, Compare, Allocator&gt;& x,
                    const multiset&lt;Key, Compare, Allocator&gt;& y);
  template&lt;class Key, class Compare, class Allocator&gt;
    bool operator&lt;=(const multiset&lt;Key, Compare, Allocator&gt;& x,
                    const multiset&lt;Key, Compare, Allocator&gt;& y);
  template&lt;class Key, class Compare, class Allocator&gt;
    bool operator&gt;=(const multiset&lt;Key, Compare, Allocator&gt;& x,
                    const multiset&lt;Key, Compare, Allocator&gt;& y);</del>

  template&lt;class Key, class Compare, class Allocator&gt;
    void swap(multiset&lt;Key, Compare, Allocator&gt;& x,
              multiset&lt;Key, Compare, Allocator&gt;& y)
      noexcept(noexcept(x.swap(y)));

  template &lt;class Key, class Compare, class Allocator, class Predicate&gt;
    void erase_if(multiset&lt;Key, Compare, Allocator&gt;& c, Predicate pred);

  namespace pmr {
    template&lt;class Key, class Compare = less&lt;Key&gt;&gt;
      using set = std::set&lt;Key, Compare, polymorphic_allocator&lt;Key&gt;&gt;;

    template&lt;class Key, class Compare = less&lt;Key&gt;&gt;
      using multiset = std::multiset&lt;Key, Compare, polymorphic_allocator&lt;Key&gt;&gt;;
  }
}</code></pre></blockquote>

<p>Change 22.4.4.1 [map.overview]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class Key, class T, class Compare = less&lt;Key&gt;,
           class Allocator = allocator&lt;pair&lt;const Key, T&gt;&gt;&gt;
  class map {
  public:
    [...]
    pair&lt;iterator, iterator&gt;               equal_range(const key_type& x);
    pair&lt;const_iterator, const_iterator&gt;   equal_range(const key_type& x) const;
    template&lt;class K&gt;
      pair&lt;iterator, iterator&gt;             equal_range(const K& x);
    template&lt;class K&gt;
      pair&lt;const_iterator, const_iterator&gt; equal_range(const K& x) const;

    <ins>friend bool operator==(const map& x, const map& y)</ins>
    <ins>  { return ranges::equal(x, y); }</ins>
    <ins>friend <i>synth-3way-result</i>&lt;value_type&gt; operator&lt;=&gt;(const map& x, const map& y)</ins>
    <ins>  { return lexicographical_compare_three_way(x.begin(), x.end(), y.begin(), y.end(), <i>synth-3way</i>); }</ins>
  };

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

<p>Change 22.4.5.1 [multimap.overview]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class Key, class T, class Compare = less&lt;Key&gt;,
           class Allocator = allocator&lt;pair&lt;const Key, T&gt;&gt;&gt;
  class multimap {
  public:
    [...]
    pair&lt;iterator, iterator&gt;               equal_range(const key_type& x);
    pair&lt;const_iterator, const_iterator&gt;   equal_range(const key_type& x) const;
    template&lt;class K&gt;
      pair&lt;iterator, iterator&gt;             equal_range(const K& x);
    template&lt;class K&gt;
      pair&lt;const_iterator, const_iterator&gt; equal_range(const K& x) const;

    <ins>friend bool operator==(const multimap& x, const multimap& y)</ins>
    <ins>  { return ranges::equal(x, y); }</ins>
    <ins>friend <i>synth-3way-result</i>&lt;value_type&gt; operator&lt;=&gt;(const multimap& x, const multimap& y)</ins>
    <ins>  { return lexicographical_compare_three_way(x.begin(), x.end(), y.begin(), y.end(), <i>synth-3way</i>); }</ins>

  };

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

<p>Change 22.4.6.1 [set.overview]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class Key, class Compare = less&lt;Key&gt;,
           class Allocator = allocator&lt;Key&gt;&gt;
  class set {
  public:
    [...]
    pair&lt;iterator, iterator&gt;               equal_range(const key_type& x);
    pair&lt;const_iterator, const_iterator&gt;   equal_range(const key_type& x) const;
    template&lt;class K&gt;
      pair&lt;iterator, iterator&gt;             equal_range(const K& x);
    template&lt;class K&gt;
      pair&lt;const_iterator, const_iterator&gt; equal_range(const K& x) const;

    <ins>friend bool operator==(const set& x, const set& y)</ins>
    <ins>  { return ranges::equal(x, y); }</ins>
    <ins>friend <i>synth-3way-result</i>&lt;value_type&gt; operator&lt;=&gt;(const set& x, const set& y)</ins>
    <ins>  { return lexicographical_compare_three_way(x.begin(), x.end(), y.begin(), y.end(), <i>synth-3way</i>); }</ins>          
  };

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

<p>Change 22.4.7.1 [multiset.overview]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class Key, class Compare = less&lt;Key&gt;,
           class Allocator = allocator&lt;Key&gt;&gt;
  class multiset {
  public:
    [...]

    pair&lt;iterator, iterator&gt;               equal_range(const key_type& x);
    pair&lt;const_iterator, const_iterator&gt;   equal_range(const key_type& x) const;
    template&lt;class K&gt;
      pair&lt;iterator, iterator&gt;             equal_range(const K& x);
    template&lt;class K&gt;
      pair&lt;const_iterator, const_iterator&gt; equal_range(const K& x) const;

    <ins>friend bool operator==(const multiset& x, const multiset& y)</ins>
    <ins>  { return ranges::equal(x, y); }</ins>
    <ins>friend <i>synth-3way-result</i>&lt;value_type&gt; operator&lt;=&gt;(const multiset& x, const multiset& y)</ins>
    <ins>  { return lexicographical_compare_three_way(x.begin(), x.end(), y.begin(), y.end(), <i>synth-3way</i>); }</ins>      
  };

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

<p>Change 22.5.2 [unord.map.syn]:</p>
<blockquote><pre><code>#include &lt;initializer_list&gt;

namespace std {
  // [unord.map], class template unordered_map
  template&lt;class Key,
           class T,
           class Hash = hash&lt;Key&gt;,
           class Pred = equal_to&lt;Key&gt;,
           class Alloc = allocator&lt;pair&lt;const Key, T&gt;&gt;&gt;
    class unordered_map;

  // [unord.multimap], class template unordered_multimap
  template&lt;class Key,
           class T,
           class Hash = hash&lt;Key&gt;,
           class Pred = equal_to&lt;Key&gt;,
           class Alloc = allocator&lt;pair&lt;const Key, T&gt;&gt;&gt;
    class unordered_multimap;

<del>  template&lt;class Key, class T, class Hash, class Pred, class Alloc&gt;
    bool operator==(const unordered_map&lt;Key, T, Hash, Pred, Alloc&gt;& a,
                    const unordered_map&lt;Key, T, Hash, Pred, Alloc&gt;& b);
  template&lt;class Key, class T, class Hash, class Pred, class Alloc&gt;
    bool operator!=(const unordered_map&lt;Key, T, Hash, Pred, Alloc&gt;& a,
                    const unordered_map&lt;Key, T, Hash, Pred, Alloc&gt;& b);

  template&lt;class Key, class T, class Hash, class Pred, class Alloc&gt;
    bool operator==(const unordered_multimap&lt;Key, T, Hash, Pred, Alloc&gt;& a,
                    const unordered_multimap&lt;Key, T, Hash, Pred, Alloc&gt;& b);
  template&lt;class Key, class T, class Hash, class Pred, class Alloc&gt;
    bool operator!=(const unordered_multimap&lt;Key, T, Hash, Pred, Alloc&gt;& a,
                    const unordered_multimap&lt;Key, T, Hash, Pred, Alloc&gt;& b);</del>

  template&lt;class Key, class T, class Hash, class Pred, class Alloc&gt;
    void swap(unordered_map&lt;Key, T, Hash, Pred, Alloc&gt;& x,
              unordered_map&lt;Key, T, Hash, Pred, Alloc&gt;& y)
      noexcept(noexcept(x.swap(y)));

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

<p>Change 22.5.3 [unord.set.syn]:</p>
<blockquote><pre><code>#include &lt;initializer_list&gt;

namespace std {
  // [unord.set], class template unordered_set
  template&lt;class Key,
           class Hash = hash&lt;Key&gt;,
           class Pred = equal_to&lt;Key&gt;,
           class Alloc = allocator&lt;Key&gt;&gt;
    class unordered_set;

  // [unord.multiset], class template unordered_multiset
  template&lt;class Key,
           class Hash = hash&lt;Key&gt;,
           class Pred = equal_to&lt;Key&gt;,
           class Alloc = allocator&lt;Key&gt;&gt;
    class unordered_multiset;

<del>  template&lt;class Key, class Hash, class Pred, class Alloc&gt;
    bool operator==(const unordered_set&lt;Key, Hash, Pred, Alloc&gt;& a,
                    const unordered_set&lt;Key, Hash, Pred, Alloc&gt;& b);
  template&lt;class Key, class Hash, class Pred, class Alloc&gt;
    bool operator!=(const unordered_set&lt;Key, Hash, Pred, Alloc&gt;& a,
                    const unordered_set&lt;Key, Hash, Pred, Alloc&gt;& b);

  template&lt;class Key, class Hash, class Pred, class Alloc&gt;
    bool operator==(const unordered_multiset&lt;Key, Hash, Pred, Alloc&gt;& a,
                    const unordered_multiset&lt;Key, Hash, Pred, Alloc&gt;& b);
  template&lt;class Key, class Hash, class Pred, class Alloc&gt;
    bool operator!=(const unordered_multiset&lt;Key, Hash, Pred, Alloc&gt;& a,
                    const unordered_multiset&lt;Key, Hash, Pred, Alloc&gt;& b);</del>

  template&lt;class Key, class Hash, class Pred, class Alloc&gt;
    void swap(unordered_set&lt;Key, Hash, Pred, Alloc&gt;& x,
              unordered_set&lt;Key, Hash, Pred, Alloc&gt;& y)
      noexcept(noexcept(x.swap(y)));

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

<p>Change 22.5.4.1 [unord.map.overview]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class Key,
           class T,
           class Hash = hash&lt;Key&gt;,
           class Pred = equal_to&lt;Key&gt;,
           class Allocator = allocator&lt;pair&lt;const Key, T&gt;&gt;&gt;
  class unordered_map {
  public:
    [...]
    // hash policy
    float load_factor() const noexcept;
    float max_load_factor() const noexcept;
    void max_load_factor(float z);
    void rehash(size_type n);
    void reserve(size_type n);

    <ins>friend bool operator==(const unordered_map& x, const unordered_map& y);</ins>
  };

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

<p>Change 22.5.5.1 [unord.multimap.overview]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class Key,
           class T,
           class Hash = hash&lt;Key&gt;,
           class Pred = equal_to&lt;Key&gt;,
           class Allocator = allocator&lt;pair&lt;const Key, T&gt;&gt;&gt;
  class unordered_multimap {
  public:
    [...]
    // hash policy
    float load_factor() const noexcept;
    float max_load_factor() const noexcept;
    void max_load_factor(float z);
    void rehash(size_type n);
    void reserve(size_type n);

    <ins>friend bool operator==(const unordered_multimap& x, const unordered_multimap& y);</ins>  
  };

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

<p>Change 22.5.6.1 [unord.set.overview]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class Key,
           class Hash = hash&lt;Key&gt;,
           class Pred = equal_to&lt;Key&gt;,
           class Allocator = allocator&lt;Key&gt;&gt;
  class unordered_set {
  public:
    [...]
    // hash policy
    float load_factor() const noexcept;
    float max_load_factor() const noexcept;
    void max_load_factor(float z);
    void rehash(size_type n);
    void reserve(size_type n);

    <ins>friend bool operator==(const unordered_set& x, const unordered_set& y);</ins>
  };

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

<p>Change 22.5.7.1 [unord.multiset.overview]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class Key,
           class Hash = hash&lt;Key&gt;,
           class Pred = equal_to&lt;Key&gt;,
           class Allocator = allocator&lt;Key&gt;&gt;
  class unordered_multiset {
  public:
    [...]
    // hash policy
    float load_factor() const noexcept;
    float max_load_factor() const noexcept;
    void max_load_factor(float z);
    void rehash(size_type n);
    void reserve(size_type n);

    <ins>friend bool operator==(const unordered_multiset& x, const unordered_multiset& y);</ins>
  };

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

<p>Change 22.6.2 [queue.syn]:</p>
<blockquote><pre><code>#include &lt;initializer_list&gt;

namespace std {
  template&lt;class T, class Container = deque&lt;T&gt;&gt; class queue;
  template&lt;class T, class Container = vector&lt;T&gt;,
           class Compare = less&lt;typename Container::value_type&gt;&gt;
    class priority_queue;

<del>  template&lt;class T, class Container&gt;
    bool operator==(const queue&lt;T, Container&gt;& x, const queue&lt;T, Container&gt;& y);
  template&lt;class T, class Container&gt;
    bool operator!=(const queue&lt;T, Container&gt;& x, const queue&lt;T, Container&gt;& y);
  template&lt;class T, class Container&gt;
    bool operator&lt; (const queue&lt;T, Container&gt;& x, const queue&lt;T, Container&gt;& y);
  template&lt;class T, class Container&gt;
    bool operator&gt; (const queue&lt;T, Container&gt;& x, const queue&lt;T, Container&gt;& y);
  template&lt;class T, class Container&gt;
    bool operator&lt;=(const queue&lt;T, Container&gt;& x, const queue&lt;T, Container&gt;& y);
  template&lt;class T, class Container&gt;
    bool operator&gt;=(const queue&lt;T, Container&gt;& x, const queue&lt;T, Container&gt;& y);</del>

  template&lt;class T, class Container&gt;
    void swap(queue&lt;T, Container&gt;& x, queue&lt;T, Container&gt;& y) noexcept(noexcept(x.swap(y)));
  template&lt;class T, class Container, class Compare&gt;
    void swap(priority_queue&lt;T, Container, Compare&gt;& x,
              priority_queue&lt;T, Container, Compare&gt;& y) noexcept(noexcept(x.swap(y)));
}</code></pre></blockquote>

<p>Change 22.6.3 [stack.syn]:</p>
<blockquote><pre><code>#include &lt;initializer_list&gt;

namespace std {
  template&lt;class T, class Container = deque&lt;T&gt;&gt; class stack;

<del>  template&lt;class T, class Container&gt;
    bool operator==(const stack&lt;T, Container&gt;& x, const stack&lt;T, Container&gt;& y);
  template&lt;class T, class Container&gt;
    bool operator!=(const stack&lt;T, Container&gt;& x, const stack&lt;T, Container&gt;& y);
  template&lt;class T, class Container&gt;
    bool operator&lt; (const stack&lt;T, Container&gt;& x, const stack&lt;T, Container&gt;& y);
  template&lt;class T, class Container&gt;
    bool operator&gt; (const stack&lt;T, Container&gt;& x, const stack&lt;T, Container&gt;& y);
  template&lt;class T, class Container&gt;
    bool operator&lt;=(const stack&lt;T, Container&gt;& x, const stack&lt;T, Container&gt;& y);
  template&lt;class T, class Container&gt;
    bool operator&gt;=(const stack&lt;T, Container&gt;& x, const stack&lt;T, Container&gt;& y);</del>

  template&lt;class T, class Container&gt;
    void swap(stack&lt;T, Container&gt;& x, stack&lt;T, Container&gt;& y) noexcept(noexcept(x.swap(y)));
}</code></pre></blockquote>

<p>Change 22.6.4.1 [queue.defn]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class T, class Container = deque&lt;T&gt;&gt;
  class queue {
  public:
    using value_type      = typename Container::value_type;
    using reference       = typename Container::reference;
    using const_reference = typename Container::const_reference;
    using size_type       = typename Container::size_type;
    using container_type  =          Container;

  protected:
    Container c;

  public:
    queue() : queue(Container()) {}
    explicit queue(const Container&);
    explicit queue(Container&&);
    template&lt;class Alloc&gt; explicit queue(const Alloc&);
    template&lt;class Alloc&gt; queue(const Container&, const Alloc&);
    template&lt;class Alloc&gt; queue(Container&&, const Alloc&);
    template&lt;class Alloc&gt; queue(const queue&, const Alloc&);
    template&lt;class Alloc&gt; queue(queue&&, const Alloc&);

    [[nodiscard]] bool empty() const    { return c.empty(); }
    size_type         size()  const     { return c.size(); }
    reference         front()           { return c.front(); }
    const_reference   front() const     { return c.front(); }
    reference         back()            { return c.back(); }
    const_reference   back() const      { return c.back(); }
    void push(const value_type& x)      { c.push_back(x); }
    void push(value_type&& x)           { c.push_back(std::move(x)); }
    template&lt;class... Args&gt;
      decltype(auto) emplace(Args&&... args)
        { return c.emplace_back(std::forward&lt;Args&gt;(args)...); }
    void pop()                          { c.pop_front(); }
    void swap(queue& q) noexcept(is_nothrow_swappable_v&lt;Container&gt;)
      { using std::swap; swap(c, q.c); }

    <ins>friend bool operator==(const queue& x, const queue& y)</ins>
    <ins>  { return x.c == y.c; }</ins>
    <ins>friend bool operator!=(const queue& x, const queue& y)</ins>
    <ins>  { return x.c != y.c; }</ins>
    <ins>friend bool operator&lt; (const queue& x, const queue& y)</ins>
    <ins>  { return x.c &lt; y.c; }</ins>
    <ins>friend bool operator&gt; (const queue& x, const queue& y)</ins>
    <ins>  { return x.c &gt; y.c; }</ins>
    <ins>friend bool operator&lt;=(const queue& x, const queue& y)</ins>
    <ins>  { return x.c &lt;= y.c; }</ins>
    <ins>friend bool operator&gt;=(const queue& x, const queue& y)</ins>
    <ins>  { return x.c &gt;= y.c; }</ins>
    <ins>friend auto operator&lt;=&gt;(const queue& x, const queue& y)</ins>
    <ins>  requires ThreeWayComparable&lt;Container&gt;</ins>
    <ins>    { return x.c &lt;=&gt; y.c; }</ins>
  };
  [...]
}</code></pre></blockquote>

<p>Remove 22.6.4.4 [queue.ops] (as we've now defined them all inline in the header):</p>
<blockquote>
<p><pre><code><del>template&lt;class T, class Container&gt;
  bool operator==(const queue&lt;T, Container&gt;&amp; x, const queue&lt;T, Container&gt;&amp; y);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">x.c == y.c</code>.</del><br />
[...]</p>
</blockquote>
<p>Change 22.6.6.1 [stack.defn]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class T, class Container = deque&lt;T&gt;&gt;
  class stack {
  public:
    using value_type      = typename Container::value_type;
    using reference       = typename Container::reference;
    using const_reference = typename Container::const_reference;
    using size_type       = typename Container::size_type;
    using container_type  = Container;

  protected:
    Container c;

  public:
    stack() : stack(Container()) {}
    explicit stack(const Container&);
    explicit stack(Container&&);
    template&lt;class Alloc&gt; explicit stack(const Alloc&);
    template&lt;class Alloc&gt; stack(const Container&, const Alloc&);
    template&lt;class Alloc&gt; stack(Container&&, const Alloc&);
    template&lt;class Alloc&gt; stack(const stack&, const Alloc&);
    template&lt;class Alloc&gt; stack(stack&&, const Alloc&);

    [[nodiscard]] bool empty() const    { return c.empty(); }
    size_type size()  const             { return c.size(); }
    reference         top()             { return c.back(); }
    const_reference   top() const       { return c.back(); }
    void push(const value_type& x)      { c.push_back(x); }
    void push(value_type&& x)           { c.push_back(std::move(x)); }
    template&lt;class... Args&gt;
      decltype(auto) emplace(Args&&... args)
        { return c.emplace_back(std::forward&lt;Args&gt;(args)...); }
    void pop()                          { c.pop_back(); }
    void swap(stack& s) noexcept(is_nothrow_swappable_v&lt;Container&gt;)
      { using std::swap; swap(c, s.c); }

    <ins>friend bool operator==(const stack& x, const stack& y)</ins>
    <ins>  { return x.c == y.c; }</ins>
    <ins>friend bool operator!=(const stack& x, const stack& y)</ins>
    <ins>  { return x.c != y.c; }</ins>
    <ins>friend bool operator&lt; (const stack& x, const stack& y)</ins>
    <ins>  { return x.c &lt; y.c; }</ins>
    <ins>friend bool operator&gt; (const stack& x, const stack& y)</ins>
    <ins>  { return x.c &gt; y.c; }</ins>
    <ins>friend bool operator&lt;=(const stack& x, const stack& y)</ins>
    <ins>  { return x.c &lt;= y.c; }</ins>
    <ins>friend bool operator&gt;=(const stack& x, const stack& y)</ins>
    <ins>  { return x.c &gt;= y.c; }</ins>
    <ins>friend auto operator&lt;=&gt;(const stack& x, const stack& y)</ins>
    <ins>  requires ThreeWayComparable&lt;Container&gt;</ins>
    <ins>    { return x.c &lt;=&gt; y.c; }</ins>      
  };

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

<p>Remove 22.6.6.4 [stack.ops] (as we've now defined them all inline in the header):</p>
<blockquote>
<p><pre><code><del>template&lt;class T, class Container&gt;
  bool operator==(const stack&lt;T, Container&gt;&amp; x, const stack&lt;T, Container&gt;&amp; y);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">x.c == y.c</code>.</del><br />
[...]</p>
</blockquote>
<h3 id="clause-23-iterators-library">4.8. Clause 23: Iterators library<a class="self-link" href="#clause-23-iterators-library"></a></h3>
<p>Change 23.2 [iterator.synopsis]:</p>
<blockquote><pre><code>#include &lt;concepts&gt;

namespace std {
  [...]
  // [predef.iterators], predefined iterators and sentinels
  // [reverse.iterators], reverse iterators
  template&lt;class Iterator&gt; class reverse_iterator;

<del>  template&lt;class Iterator1, class Iterator2&gt;
    constexpr bool operator==(
      const reverse_iterator&lt;Iterator1&gt;& x,
      const reverse_iterator&lt;Iterator2&gt;& y);
  template&lt;class Iterator1, class Iterator2&gt;
    constexpr bool operator!=(
      const reverse_iterator&lt;Iterator1&gt;& x,
      const reverse_iterator&lt;Iterator2&gt;& y);
  template&lt;class Iterator1, class Iterator2&gt;
    constexpr bool operator&lt;(
      const reverse_iterator&lt;Iterator1&gt;& x,
      const reverse_iterator&lt;Iterator2&gt;& y);
  template&lt;class Iterator1, class Iterator2&gt;
    constexpr bool operator&gt;(
      const reverse_iterator&lt;Iterator1&gt;& x,
      const reverse_iterator&lt;Iterator2&gt;& y);
  template&lt;class Iterator1, class Iterator2&gt;
    constexpr bool operator&lt;=(
      const reverse_iterator&lt;Iterator1&gt;& x,
      const reverse_iterator&lt;Iterator2&gt;& y);
  template&lt;class Iterator1, class Iterator2&gt;
    constexpr bool operator&gt;=(
      const reverse_iterator&lt;Iterator1&gt;& x,
      const reverse_iterator&lt;Iterator2&gt;& y);</del>
  [...]

  // [move.iterators], move iterators and sentinels
  template&lt;class Iterator&gt; class move_iterator;

<del>  template&lt;class Iterator1, class Iterator2&gt;
    constexpr bool operator==(
      const move_iterator&lt;Iterator1&gt;& x, const move_iterator&lt;Iterator2&gt;& y);
  template&lt;class Iterator1, class Iterator2&gt;
    constexpr bool operator!=(
      const move_iterator&lt;Iterator1&gt;& x, const move_iterator&lt;Iterator2&gt;& y);
  template&lt;class Iterator1, class Iterator2&gt;
    constexpr bool operator&lt;(
      const move_iterator&lt;Iterator1&gt;& x, const move_iterator&lt;Iterator2&gt;& y);
  template&lt;class Iterator1, class Iterator2&gt;
    constexpr bool operator&gt;(
      const move_iterator&lt;Iterator1&gt;& x, const move_iterator&lt;Iterator2&gt;& y);
  template&lt;class Iterator1, class Iterator2&gt;
    constexpr bool operator&lt;=(
      const move_iterator&lt;Iterator1&gt;& x, const move_iterator&lt;Iterator2&gt;& y);
  template&lt;class Iterator1, class Iterator2&gt;
    constexpr bool operator&gt;=(
      const move_iterator&lt;Iterator1&gt;& x, const move_iterator&lt;Iterator2&gt;& y);</del>

  [...]

  // [stream.iterators], stream iterators
  template&lt;class T, class charT = char, class traits = char_traits&lt;charT&gt;,
           class Distance = ptrdiff_t&gt;
  class istream_iterator;
<del>  template&lt;class T, class charT, class traits, class Distance&gt;
    bool operator==(const istream_iterator&lt;T,charT,traits,Distance&gt;& x,
            const istream_iterator&lt;T,charT,traits,Distance&gt;& y);
  template&lt;class T, class charT, class traits, class Distance&gt;
    bool operator!=(const istream_iterator&lt;T,charT,traits,Distance&gt;& x,
            const istream_iterator&lt;T,charT,traits,Distance&gt;& y);</del>

  template&lt;class T, class charT = char, class traits = char_traits&lt;charT&gt;&gt;
      class ostream_iterator;

  template&lt;class charT, class traits = char_traits&lt;charT&gt;&gt;
    class istreambuf_iterator;
<del>  template&lt;class charT, class traits&gt;
    bool operator==(const istreambuf_iterator&lt;charT,traits&gt;& a,
            const istreambuf_iterator&lt;charT,traits&gt;& b);
  template&lt;class charT, class traits&gt;
    bool operator!=(const istreambuf_iterator&lt;charT,traits&gt;& a,
            const istreambuf_iterator&lt;charT,traits&gt;& b);</del>

  template&lt;class charT, class traits = char_traits&lt;charT&gt;&gt;
    class ostreambuf_iterator;  
  [...]
}</code></pre></blockquote>

<p>Change 23.5.1.1 [reverse.iterator]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class Iterator&gt;
  class reverse_iterator {
  public:
    [...]
    template&lt;IndirectlySwappable&lt;Iterator&gt; Iterator2&gt;
      friend constexpr void
        iter_swap(const reverse_iterator& x,
                  const reverse_iterator&lt;Iterator2&gt;& y) noexcept(see below);

<ins>    // [reverse.iter.cmp] Comparisons
    template&lt;class Iterator2&gt;
      friend constexpr bool operator==(const reverse_iterator& x,
                                       const reverse_iterator&lt;Iterator2&gt;& y)
      { see below }
    template&lt;class Iterator2&gt;
      friend constexpr bool operator!=(const reverse_iterator& x,
                                       const reverse_iterator&lt;Iterator2&gt;& y)
      { see below }
    template&lt;class Iterator2&gt;
      friend constexpr bool operator&lt; (const reverse_iterator& x,
                                       const reverse_iterator&lt;Iterator2&gt;& y)
      { see below }
    template&lt;class Iterator2&gt;
      friend constexpr bool operator&gt; (const reverse_iterator& x,
                                       const reverse_iterator&lt;Iterator2&gt;& y)
      { see below }
    template&lt;class Iterator2&gt;
      friend constexpr bool operator&lt;=(const reverse_iterator& x,
                                       const reverse_iterator&lt;Iterator2&gt;& y)
      { see below }
    template&lt;class Iterator2&gt;
      friend constexpr bool operator&gt;=(const reverse_iterator& x,
                                       const reverse_iterator&lt;Iterator2&gt;& y)
      { see below }
    template&lt;ThreeWayComparableWith&lt;Iterator&gt; Iterator2&gt;
      friend constexpr compare_three_way_result_t&lt;Iterator, Iterator2&gt;
        operator&lt;=&gt;(const reverse_iterator& x,
                    const reverse_iterator&lt;Iterator2&gt;& y)
        { see below }</ins>

  protected:
    Iterator current;
  };
}</code></pre></blockquote>

<p>Change 23.5.1.7 [reverse.iter.cmp]:</p>
<blockquote>
<p><pre><code>template&lt;<del>class Iterator1, </del>class Iterator2&gt;
  <ins>friend </ins>constexpr bool operator==(
    const reverse_iterator<del>&lt;Iterator1&gt;</del>&amp; x,
    const reverse_iterator&lt;Iterator2&gt;&amp; y);</code></pre>
<em>Constraints</em>: <code class="language-cpp">x.current == y.current</code> is well-formed and convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: <code class="language-cpp">x.current == y.current</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class Iterator1, </del>class Iterator2&gt;
  <ins>friend </ins>constexpr bool operator!=(
    const reverse_iterator<del>&lt;Iterator1&gt;</del>&amp; x,
    const reverse_iterator&lt;Iterator2&gt;&amp; y);</code></pre>
<em>Constraints</em>: <code class="language-cpp">x.current != y.current</code> is well-formed and convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: <code class="language-cpp">x.current != y.current</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class Iterator1, </del>class Iterator2&gt;
  <ins>friend </ins>constexpr bool operator&lt;(
    const reverse_iterator<del>&lt;Iterator1&gt;</del>&amp; x,
    const reverse_iterator&lt;Iterator2&gt;&amp; y);</code></pre>
<em>Constraints</em>: <code class="language-cpp">x.current &gt; y.current</code> is well-formed and convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: <code class="language-cpp">x.current &gt; y.current</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class Iterator1, </del>class Iterator2&gt;
  <ins>friend </ins>constexpr bool operator&gt;(
    const reverse_iterator<del>&lt;Iterator1&gt;</del>&amp; x,
    const reverse_iterator&lt;Iterator2&gt;&amp; y);</code></pre>
<em>Constraints</em>: <code class="language-cpp">x.current &lt; y.current</code> is well-formed and convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: <code class="language-cpp">x.current &lt; y.current</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class Iterator1, </del>class Iterator2&gt;
  <ins>friend </ins>constexpr bool operator&lt;=(
    const reverse_iterator<del>&lt;Iterator1&gt;</del>&amp; x,
    const reverse_iterator&lt;Iterator2&gt;&amp; y);</code></pre>
<em>Constraints</em>: <code class="language-cpp">x.current &gt;= y.current</code> is well-formed and convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: <code class="language-cpp">x.current &gt;= y.current</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class Iterator1, </del>class Iterator2&gt;
  <ins>friend </ins>constexpr bool operator&gt;=(
    const reverse_iterator<del>&lt;Iterator1&gt;</del>&amp; x,
    const reverse_iterator&lt;Iterator2&gt;&amp; y);</code></pre>
<em>Constraints</em>: <code class="language-cpp">x.current &lt;= y.current</code> is well-formed and convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: <code class="language-cpp">x.current &lt;= y.current</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><ins>template&lt;ThreeWayComparableWith&lt;Iterator&gt; Iterator2&gt;
  friend constexpr compare_three_way_result_t&lt;Iterator, Iterator2&gt; operator&lt;=&gt;(
    const reverse_iterator&amp; x,
    const reverse_iterator&lt;Iterator2&gt;&amp; y);</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">y.current &lt;=&gt; x.current</code>.</ins><br />
<ins><em>Remarks</em>: This function is more constrained than ([temp.constr.order]) each of the other relational operator function templates. This function is to be found via argument-dependent lookup only.</ins></p>
</blockquote>
<p>Change 23.5.3.1 [move.iterator]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class Iterator&gt;
  class move_iterator {
    [...]
<ins>    // [move.iter.op.comp] Comparisons
    template&lt;class Iterator2&gt;
      friend constexpr bool operator==(const move_iterator& x, const move_iterator&lt;Iterator2&gt;& y)
      { see below }
    template&lt;class Iterator2&gt;
      friend constexpr bool operator&lt;(const move_iterator& x, const move_iterator&lt;Iterator2&gt;& y)
      { see below }
    template&lt;class Iterator2&gt;
      friend constexpr bool operator&gt;(const move_iterator& x, const move_iterator&lt;Iterator2&gt;& y)
      { see below }
    template&lt;class Iterator2&gt;
      friend constexpr bool operator&lt;=(const move_iterator& x, const move_iterator&lt;Iterator2&gt;& y)
      { see below }
    template&lt;class Iterator2&gt;
      friend constexpr bool operator&gt;=(const move_iterator& x, const move_iterator&lt;Iterator2&gt;& y)
      { see below }
    template&lt;ThreeWayComparableWith&lt;Iterator&gt; Iterator2&gt;
      friend constexpr compare_three_way_result_t&lt;Iterator, Iterator2&gt;
        operator&lt;=&gt;(const move_iterator& x, const move_iterator&lt;Iterator2&gt;& y)
        { see below }</ins>

    template&lt;Sentinel&lt;Iterator&gt; S&gt;
      friend constexpr bool
        operator==(const move_iterator& x, const move_sentinel&lt;S&gt;& y);
<del>    template&lt;Sentinel&lt;Iterator&gt; S&gt;
      friend constexpr bool
        operator==(const move_sentinel&lt;S&gt;& x, const move_iterator& y);
    template&lt;Sentinel&lt;Iterator&gt; S&gt;
      friend constexpr bool
        operator!=(const move_iterator& x, const move_sentinel&lt;S&gt;& y);
    template&lt;Sentinel&lt;Iterator&gt; S&gt;
      friend constexpr bool
        operator!=(const move_sentinel&lt;S&gt;& x, const move_iterator& y);</del>
    template&lt;SizedSentinel&lt;Iterator&gt; S&gt;
      friend constexpr iter_difference_t&lt;Iterator&gt;
        operator-(const move_sentinel&lt;S&gt;& x, const move_iterator& y);
    [...]
  private:
    Iterator current;   // exposition only
  };
}</code></pre></blockquote>

<p>Change 23.5.3.7 [move.iter.op.comp]:</p>
<blockquote>
<p><pre><code>template&lt;<del>class Iterator1, </del>class Iterator2&gt;
  <ins>friend </ins>constexpr bool operator==(const move_iterator<del>&lt;Iterator1&gt;</del>&amp; x,
                            const move_iterator&lt;Iterator2&gt;&amp; y);
template&lt;Sentinel&lt;Iterator&gt; S&gt;
  friend constexpr bool operator==(const move_iterator&amp; x,
                                   const move_sentinel&lt;S&gt;&amp; y);
template&lt;Sentinel&lt;Iterator&gt; S&gt;
  friend constexpr bool operator==(const move_sentinel&lt;S&gt;&amp; x,
                                   const move_iterator&amp; y);</code></pre>
<em>Constraints</em>: <code class="language-cpp">x.base() == y.base()</code> is well-formed and convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: <code class="language-cpp">x.base() == y.base()</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><del>template&lt;class Iterator1, class Iterator2&gt;
  constexpr bool operator!=(const move_iterator&lt;Iterator1&gt;&amp; x,
                            const move_iterator&lt;Iterator2&gt;&amp; y);
template&lt;Sentinel&lt;Iterator&gt; S&gt;
  friend constexpr bool operator!=(const move_iterator&amp; x,
                                   const move_sentinel&lt;S&gt;&amp; y);
template&lt;Sentinel&lt;Iterator&gt; S&gt;
  friend constexpr bool operator!=(const move_sentinel&lt;S&gt;&amp; x,
                                   const move_iterator&amp; y);</del></code></pre>
<del><em>Constraints</em>: <code class="language-cpp">x.base() == y.base()</code> is well-formed and convertible to <code class="language-cpp">bool</code>.</del><br />
<del><em>Returns</em>: <code class="language-cpp">!(x == y)</code>.</del>
<pre><code>template&lt;<del>class Iterator1, </del>class Iterator2&gt;
<ins>friend </ins>constexpr bool operator&lt;(const move_iterator<del>&lt;Iterator1&gt;</del>&amp; x, const move_iterator&lt;Iterator2&gt;&amp; y);</code></pre>
<em>Constraints</em>: <code class="language-cpp">x.base() &lt; y.base()</code> is well-formed and convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: <code class="language-cpp">x.base() &lt; y.base()</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class Iterator1, </del>class Iterator2&gt;
<ins>friend </ins>constexpr bool operator&gt;(const move_iterator<del>&lt;Iterator1&gt;</del>&amp; x, const move_iterator&lt;Iterator2&gt;&amp; y);</code></pre>
<em>Constraints</em>: <code class="language-cpp">y.base() &lt; x.base()</code> is well-formed and convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: <code class="language-cpp">y &lt; x</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class Iterator1, </del>class Iterator2&gt;
<ins>friend </ins>constexpr bool operator&lt;=(const move_iterator<del>&lt;Iterator1&gt;</del>&amp; x, const move_iterator&lt;Iterator2&gt;&amp; y);</code></pre>
<em>Constraints</em>: <code class="language-cpp">y.base() &lt; x.base()</code> is well-formed and convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: <code class="language-cpp">!(y &lt; x)</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code>template&lt;<del>class Iterator1, </del>class Iterator2&gt;
<ins>friend </ins>constexpr bool operator&gt;=(const move_iterator<del>&lt;Iterator1&gt;</del>&amp; x, const move_iterator&lt;Iterator2&gt;&amp; y);</code></pre>
<em>Constraints</em>: <code class="language-cpp">x.base() &lt; y.base()</code> is well-formed and convertible to <code class="language-cpp">bool</code>.<br />
<em>Returns</em>: <code class="language-cpp">!(x &lt; y)</code>.<br />
<ins><em>Remarks</em>: This function is to be found via argument-dependent lookup only.</ins>
<pre><code><ins>template&lt;ThreeWayComparableWith&lt;Iterator&gt; Iterator2&gt;
  friend constexpr compare_three_way_result_t&lt;Iterator, Iterator2&gt; operator&lt;=&gt;(
    const move_iterator&amp; x,
    const move_iterator&lt;Iterator2&gt;&amp; y);</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">x.base() &lt;=&gt; y.base()</code>.</ins><br />
<ins><em>Remarks</em>: This function is more constrained than ([temp.constr.order]) each of the other relational operator function templates. This function is to be found via argument-dependent lookup only.</ins></p>
</blockquote>
<p>Remove the <code class="language-cpp">operator!=</code> from 23.5.4.1 [common.iterator]:</p>
<blockquote><pre><code>namespace std {
  template&lt;Iterator I, Sentinel&lt;I&gt; S&gt;
    requires (!Same&lt;I, S&gt;)
  class common_iterator {
  public:
    [...]
    template&lt;class I2, Sentinel&lt;I&gt; S2&gt;
      requires Sentinel&lt;S, I2&gt;
    friend bool operator==(
      const common_iterator& x, const common_iterator&lt;I2, S2&gt;& y);
    template&lt;class I2, Sentinel&lt;I&gt; S2&gt;
      requires Sentinel&lt;S, I2&gt; && EqualityComparableWith&lt;I, I2&gt;
    friend bool operator==(
      const common_iterator& x, const common_iterator&lt;I2, S2&gt;& y);
<del>    template&lt;class I2, Sentinel&lt;I&gt; S2&gt;
      requires Sentinel&lt;S, I2&gt;
    friend bool operator!=(
      const common_iterator& x, const common_iterator&lt;I2, S2&gt;& y);</del>
    [...]
  private:
    variant&lt;I, S&gt; v_;   // exposition only
  };
  [...]
}</code></pre></blockquote>

<p>Remove the <code class="language-cpp">operator!=</code> from 23.5.4.6 [common.iter.cmp]:</p>
<blockquote>
<p><pre><code><del>template&lt;class I2, Sentinel&lt;I&gt; S2&gt;
  requires Sentinel&lt;S, I2&gt;
friend bool operator!=(
  const common_iterator&amp; x, const common_iterator&lt;I2, S2&gt;&amp; y);</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x == y);</code></del></p>
</blockquote>
<p>Change 23.5.6.1 [counted.iterator]:</p>
<blockquote><pre><code>namespace std {
  template&lt;Iterator I&gt;
  class counted_iterator {
  public:
    using iterator_type = I;
    [...]
    template&lt;Common&lt;I&gt; I2&gt;
      friend constexpr bool operator==(
        const counted_iterator& x, const counted_iterator&lt;I2&gt;& y);
    friend constexpr bool operator==(
      const counted_iterator& x, default_sentinel_t);
    <del>friend constexpr bool operator==(</del>
    <del>  default_sentinel_t, const counted_iterator& x);</del>

    <del>template&lt;Common&lt;I&gt; I2&gt;</del>
    <del>  friend constexpr bool operator!=(</del>
    <del>    const counted_iterator& x, const counted_iterator&lt;I2&gt;& y);</del>
    <del>friend constexpr bool operator!=(</del>
    <del>  const counted_iterator& x, default_sentinel_t y);</del>
    <del>friend constexpr bool operator!=(</del>
    <del>  default_sentinel_t x, const counted_iterator& y);</del>

    template&lt;Common&lt;I&gt; I2&gt;
      friend constexpr bool operator&lt;(
        const counted_iterator& x, const counted_iterator&lt;I2&gt;& y);
    template&lt;Common&lt;I&gt; I2&gt;
      friend constexpr bool operator&gt;(
        const counted_iterator& x, const counted_iterator&lt;I2&gt;& y);
    template&lt;Common&lt;I&gt; I2&gt;
      friend constexpr bool operator&lt;=(
        const counted_iterator& x, const counted_iterator&lt;I2&gt;& y);
    template&lt;Common&lt;I&gt; I2&gt;
      friend constexpr bool operator&gt;=(
        const counted_iterator& x, const counted_iterator&lt;I2&gt;& y);
    <ins>template&lt;Common&lt;I&gt; I2&gt; requires ThreeWayComparableWith&lt;I, I2&gt;</ins>
    <ins>  friend constexpr compare_three_way_result_t&lt;I, I2&gt; operator&lt;=&gt;(</ins>
    <ins>    const counted_iterator& x, const counted_iterator&lt;I2&gt;& y);</ins>

    friend constexpr iter_rvalue_reference_t&lt;I&gt; iter_move(const counted_iterator& i)
      noexcept(noexcept(ranges::iter_move(i.current)))
        requires InputIterator&lt;I&gt;;
    template&lt;IndirectlySwappable&lt;I&gt; I2&gt;
      friend constexpr void iter_swap(const counted_iterator& x, const counted_iterator&lt;I2&gt;& y)
        noexcept(noexcept(ranges::iter_swap(x.current, y.current)));

  private:
    I current = I();                    // exposition only
    iter_difference_t&lt;I&gt; length = 0;    // exposition only
  };
  [...]
}</code></pre></blockquote>

<p>Change 23.5.6.6 [counted.iter.cmp]:</p>
<blockquote>
<p><pre><code>template&lt;Common&lt;I&gt; I2&gt;
  friend constexpr bool operator==(
    const counted_iterator&amp; x, const counted_iterator&lt;I2&gt;&amp; y);</code></pre>
<em>Expects</em>: <code class="language-cpp">x</code> and <code class="language-cpp">y</code> refer to elements of the same sequence ([counted.iterator]).<br />
<em>Effects</em>: Equivalent to: return <code class="language-cpp">x.length == y.length;</code>
<pre><code>friend constexpr bool operator==(
  const counted_iterator&amp; x, default_sentinel_t);
<del>friend constexpr bool operator==(</del>
<del>  default_sentinel_t, const counted_iterator&amp; x);</del></code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return x.length == 0;</code>
<pre><code><del>template&lt;Common&lt;I&gt; I2&gt;
  friend constexpr bool operator!=(
    const counted_iterator&amp; x, const counted_iterator&lt;I2&gt;&amp; y);
friend constexpr bool operator!=(
  const counted_iterator&amp; x, default_sentinel_t y);
friend constexpr bool operator!=(
  default_sentinel_t x, const counted_iterator&amp; y);</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x == y);</code></del>
<pre><code>template&lt;Common&lt;I&gt; I2&gt;
  friend constexpr bool operator&lt;(
    const counted_iterator&amp; x, const counted_iterator&lt;I2&gt;&amp; y);</code></pre>
<em>Expects</em>: <code class="language-cpp">x</code> and <code class="language-cpp">y</code> refer to elements of the same sequence ([counted.iterator]).<br />
<em>Effects</em>: Equivalent to: <code class="language-cpp">return y.length &lt; x.length;</code><br />
[<em>Note</em>: The argument order in the <em>Effects</em>: element is reversed because length counts down, not up. —<em>end note</em>]
<pre><code>template&lt;Common&lt;I&gt; I2&gt;
  friend constexpr bool operator&gt;(
    const counted_iterator&amp; x, const counted_iterator&lt;I2&gt;&amp; y);</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return y &lt; x;</code>
<pre><code>template&lt;Common&lt;I&gt; I2&gt;
  friend constexpr bool operator&lt;=(
    const counted_iterator&amp; x, const counted_iterator&lt;I2&gt;&amp; y);</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return !(y &lt; x);</code>
<pre><code>template&lt;Common&lt;I&gt; I2&gt;
  friend constexpr bool operator&gt;=(
    const counted_iterator&amp; x, const counted_iterator&lt;I2&gt;&amp; y);</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x &lt; y);</code>
<pre><code><ins>template&lt;Common&lt;I&gt; I2&gt; requires ThreeWayComparableWith&lt;I, I2&gt;
  friend constexpr compare_three_way_result_t&lt;I, I2&gt; operator&lt;=&gt;(
    const counted_iterator&amp; x, const counted_iterator&lt;I2&gt;&amp; y);</ins></code></pre>
<ins><em>Effects</em>: Equivalent to: <code class="language-cpp">return y &lt;=&gt; x;</code></ins></p>
</blockquote>
<p>Change 23.5.7.1 [unreachable.sentinel]:</p>
<blockquote><pre><code>namespace std {
  struct unreachable_sentinel_t {
    template&lt;WeaklyIncrementable I&gt;
      friend constexpr bool operator==(unreachable_sentinel_t, const I&) noexcept<del>;</del>
      <ins>{ return true; }</ins>
<del>    template&lt;WeaklyIncrementable I&gt;
      friend constexpr bool operator==(const I&, unreachable_sentinel_t) noexcept;
    template&lt;WeaklyIncrementable I&gt;
      friend constexpr bool operator!=(unreachable_sentinel_t, const I&) noexcept;
    template&lt;WeaklyIncrementable I&gt;
      friend constexpr bool operator!=(const I&, unreachable_sentinel_t) noexcept;</del>
  };
}</code></pre></blockquote>

<p>Remove 23.5.7.2 [unreachable.sentinel.cmp] (as it's now entirely defined in the synopsis):</p>
<blockquote>
<p><pre><code><del>template&lt;WeaklyIncrementable I&gt;
  friend constexpr bool operator==(unreachable_sentinel_t, const I&amp;) noexcept;
template&lt;WeaklyIncrementable I&gt;
  friend constexpr bool operator==(const I&amp;, unreachable_sentinel_t) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">false</code>.</del>
<pre><code><del>template&lt;WeaklyIncrementable I&gt;
  friend constexpr bool operator!=(unreachable_sentinel_t, const I&amp;) noexcept;
template&lt;WeaklyIncrementable I&gt;
  friend constexpr bool operator!=(const I&amp;, unreachable_sentinel_t) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">true</code>.</del></p>
</blockquote>
<p>Change 23.6.1 [istream.iterator]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class T, class charT = char, class traits = char_traits&lt;charT&gt;,
           class Distance = ptrdiff_t&gt;
  class istream_iterator {
  public:
    using iterator_category = input_iterator_tag;
    using value_type        = T;
    using difference_type   = Distance;
    using pointer           = const T*;
    using reference         = const T&;
    using char_type         = charT;
    using traits_type       = traits;
    using istream_type      = basic_istream&lt;charT,traits&gt;;

    constexpr istream_iterator();
    constexpr istream_iterator(default_sentinel_t);
    istream_iterator(istream_type& s);
    istream_iterator(const istream_iterator& x) = default;
    ~istream_iterator() = default;
    istream_iterator& operator=(const istream_iterator&) = default;

    const T& operator*() const;
    const T* operator-&gt;() const;
    istream_iterator& operator++();
    istream_iterator  operator++(int);

    friend bool operator==(const istream_iterator& i, default_sentinel_t)<del>;</del>
    <ins>{ return !i.in_stream; }</ins>
    <ins>friend bool operator==(const istream_iterator& x, const istream_iterator& y)</ins>
    <ins>{ return x.in_stream == y.in_stream; }</ins>
    <del>friend bool operator==(default_sentinel_t, const istream_iterator& i);</del>
    <del>friend bool operator!=(const istream_iterator& x, default_sentinel_t y);</del>
    <del>friend bool operator!=(default_sentinel_t x, const istream_iterator& y);</del>

  private:
    basic_istream&lt;charT,traits&gt;* in_stream; // exposition only
    T value;                                // exposition only
  };
}</code></pre></blockquote>

<p>Remove the specifications for <code class="language-cpp">operator==</code> and <code class="language-cpp">operator!=</code> from 23.6.1.2 [istream.iterator.ops]:</p>
<blockquote>
<p><pre><code><del>template&lt;class T, class charT, class traits, class Distance&gt;
  bool operator==(const istream_iterator&lt;T,charT,traits,Distance&gt;&amp; x,
                  const istream_iterator&lt;T,charT,traits,Distance&gt;&amp; y);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">x.in_stream == y.in_stream</code>.</del>
<pre><code><del>friend bool operator==(default_sentinel_t, const istream_iterator&amp; i);
friend bool operator==(const istream_iterator&amp; i, default_sentinel_t);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!i.in_stream</code>.</del>
<pre><code><del>template&lt;class T, class charT, class traits, class Distance&gt;
  bool operator!=(const istream_iterator&lt;T,charT,traits,Distance&gt;&amp; x,
                  const istream_iterator&lt;T,charT,traits,Distance&gt;&amp; y);
friend bool operator!=(default_sentinel_t x, const istream_iterator&amp; y);
friend bool operator!=(const istream_iterator&amp; x, default_sentinel_t y);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(x == y)</code></del></p>
</blockquote>
<p>Change 23.6.3 [istreambuf.iterator]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class charT, class traits = char_traits&lt;charT&gt;&gt;
  class istreambuf_iterator {
  public:
    [...]
    bool equal(const istreambuf_iterator& b) const;

    <del>friend bool operator==(default_sentinel_t s, const istreambuf_iterator& i);</del>
    friend bool operator==(const istreambuf_iterator& i, default_sentinel_t s)<del>;</del>
    <ins>{ return i.equal(s); }</ins>
    <del>friend bool operator!=(default_sentinel_t a, const istreambuf_iterator& b);</del>
    <del>friend bool operator!=(const istreambuf_iterator& a, default_sentinel_t b);</del>
    <ins>friend bool operator==(const istreambuf_iterator& a, const istreambuf_iterator& b)</ins>
    <ins>{ return a.equal(b); }</ins>

  private:
    streambuf_type* sbuf_;                // exposition only
  };
}</code></pre></blockquote>

<p>Remove the specifications for <code class="language-cpp">operator==</code> and <code class="language-cpp">operator!=</code> from 23.6.3.3 [istreambuf.iterator.ops]:</p>
<blockquote>
<p><pre><code><del>template&lt;class charT, class traits&gt;
  bool operator==(const istreambuf_iterator&lt;charT,traits&gt;&amp; a,
                  const istreambuf_iterator&lt;charT,traits&gt;&amp; b);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">a.equal(b)</code>.</del>
<pre><code><del>friend bool operator==(default_sentinel_t s, const istreambuf_iterator&amp; i);
friend bool operator==(const istreambuf_iterator&amp; i, default_sentinel_t s);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">i.equal(s)</code>.</del>
<pre><code><del>template&lt;class charT, class traits&gt;
  bool operator!=(const istreambuf_iterator&lt;charT,traits&gt;&amp; a,
                  const istreambuf_iterator&lt;charT,traits&gt;&amp; b);
friend bool operator!=(default_sentinel_t a, const istreambuf_iterator&amp; b);
friend bool operator!=(const istreambuf_iterator&amp; a, default_sentinel_t b);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!a.equal(b)</code>.</del></p>
</blockquote>
<h3 id="clause-24-ranges-library">4.9. Clause 24: Ranges library<a class="self-link" href="#clause-24-ranges-library"></a></h3>
<p>Change 24.6.3.3 [range.iota.iterator]:</p>
<blockquote><pre><code>namespace std::ranges {
  template&lt;class W, class Bound&gt;
  struct iota_view&lt;W, Bound&gt;::iterator {
  private:
    W value_ = W();             // exposition only
  public:
    [...]

    friend constexpr bool operator==(const iterator& x, const iterator& y)
      requires EqualityComparable&lt;W&gt;;
    <del>friend constexpr bool operator!=(const iterator& x, const iterator& y)</del>
    <del>  requires EqualityComparable&lt;W&gt;;</del>

    friend constexpr bool operator&lt;(const iterator& x, const iterator& y)
      requires StrictTotallyOrdered&lt;W&gt;;
    friend constexpr bool operator&gt;(const iterator& x, const iterator& y)
      requires StrictTotallyOrdered&lt;W&gt;;
    friend constexpr bool operator&lt;=(const iterator& x, const iterator& y)
      requires StrictTotallyOrdered&lt;W&gt;;
    friend constexpr bool operator&gt;=(const iterator& x, const iterator& y)
      requires StrictTotallyOrdered&lt;W&gt;;
    <ins>friend constexpr compare_three_way_result_t&lt;W&gt; operator&lt;=&gt;(const iterator& x, const iterator& y)</ins>
    <ins>  requires StrictTotallyOrdered&lt;W&gt; && ThreeWayComparable&lt;W&gt;</ins>

    [...]
  };
}</code></pre></blockquote>

<p>Change 24.6.3.3 [range.iota.iterator], paragraphs 14-20:</p>
<blockquote>
<p><pre><code>friend constexpr bool operator==(const iterator&amp; x, const iterator&amp; y)
  requires EqualityComparable&lt;W&gt;;</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return x.value_ == y.value_;</code>
<pre><code><del>friend constexpr bool operator!=(const iterator&amp; x, const iterator&amp; y)
  requires EqualityComparable&lt;W&gt;;</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x == y);</code></del>
<pre><code>friend constexpr bool operator&lt;(const iterator&amp; x, const iterator&amp; y)
  requires StrictTotallyOrdered&lt;W&gt;;</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return x.value_ &lt; y.value_;</code><br />
[...]
<pre><code>friend constexpr bool operator&gt;=(const iterator&amp; x, const iterator&amp; y)
  requires StrictTotallyOrdered&lt;W&gt;;</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x &lt; y);</code>
<pre><code><ins>friend constexpr compare_three_way_result_t&lt;W&gt; operator&lt;=&gt;(const iterator&amp; x, const iterator&amp; y)
  requires StrictTotallyOrdered&lt;W&gt; &amp;&amp; ThreeWayComparable&lt;W&gt;;</ins></code></pre>
<ins><em>Effects</em>: Equivalent to: <code class="language-cpp">return x.value_ &lt;=&gt; y.value_;</code></ins></p>
</blockquote>
<p>Remove obsolete equality operators 24.6.3.4 [range.iota.sentinel]:</p>
<blockquote>
<p><pre><code>namespace std::ranges {
  template&lt;class W, class Bound&gt;
  struct iota_view&lt;W, Bound&gt;::sentinel {
  private:
    Bound bound_ = Bound();     // exposition only
  public:
    sentinel() = default;
    constexpr explicit sentinel(Bound bound);
    friend constexpr bool operator==(const iterator&amp; x, const sentinel&amp; y);
    <del>friend constexpr bool operator==(const sentinel&amp; x, const iterator&amp; y);</del>
    <del>friend constexpr bool operator!=(const iterator&amp; x, const sentinel&amp; y);</del>
    <del>friend constexpr bool operator!=(const sentinel&amp; x, const iterator&amp; y);</del>
  };
}</code></pre></p>
<p><pre><code>constexpr explicit sentinel(Bound bound);</code></pre>
<em>Effects</em>: Initializes <code class="language-cpp">bound_</code> with <code class="language-cpp">bound</code>.
<pre><code>friend constexpr bool operator==(const iterator&amp; x, const sentinel&amp; y);</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return x.value_ == y.bound_;</code>
<pre><code><del>friend constexpr bool operator==(const sentinel&amp; x, const iterator&amp; y);</del></code></pre>
<del><em>Effects</em>: Equivalent to: return y == x;</del>
<pre><code><del>friend constexpr bool operator!=(const iterator&amp; x, const sentinel&amp; y);</del></code></pre>
<del><em>Effects</em>: Equivalent to: return !(x == y);</del>
<pre><code><del>friend constexpr bool operator!=(const sentinel&amp; x, const iterator&amp; y);</del></code></pre>
<del><em>Effects</em>: Equivalent to: return !(y == x);</del></p>
</blockquote>
<p>Remove <code class="language-cpp">operator!=</code> from 24.7.4.3 [range.filter.iterator]:</p>
<blockquote><pre><code>namespace std::ranges {
  template&lt;class V, class Pred&gt;
  class filter_view&lt;V, Pred&gt;::iterator {
  private:
    iterator_t&lt;V&gt; current_ = iterator_t&lt;V&gt;();   // exposition only
    filter_view* parent_ = nullptr;             // exposition only
  public:
    [...]
    friend constexpr bool operator==(const iterator& x, const iterator& y)
      requires EqualityComparable&lt;iterator_t&lt;V&gt;&gt;;
    <del>friend constexpr bool operator!=(const iterator& x, const iterator& y)</del>
    <del>  requires EqualityComparable&lt;iterator_t&lt;V&gt;&gt;;</del>
    [...]
  };
}</code></pre></blockquote>

<p>and</p>
<blockquote>
<p><pre><code>friend constexpr bool operator==(const iterator&amp; x, const iterator&amp; y)
  requires EqualityComparable&lt;iterator_t&lt;V&gt;&gt;;</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return x.current_ == y.current_;</code>
<pre><code><del>friend constexpr bool operator!=(const iterator&amp; x, const iterator&amp; y)
  requires EqualityComparable&lt;iterator_t&lt;V&gt;&gt;;</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x == y);</code></del></p>
</blockquote>
<p>Remove obsolete equality operators from 24.7.4.4 [range.filter.sentinel]:</p>
<blockquote>
<p><pre><code>namespace std::ranges {
  template&lt;class V, class Pred&gt;
  class filter_view&lt;V, Pred&gt;::sentinel {
  private:
    sentinel_t&lt;V&gt; end_ = sentinel_t&lt;V&gt;();       // exposition only
  public:
    sentinel() = default;
    constexpr explicit sentinel(filter_view&amp; parent);
    constexpr sentinel_t&lt;V&gt; base() const;
    friend constexpr bool operator==(const iterator&amp; x, const sentinel&amp; y);
    <del>friend constexpr bool operator==(const sentinel&amp; x, const iterator&amp; y);</del>
    <del>friend constexpr bool operator!=(const iterator&amp; x, const sentinel&amp; y);</del>
    <del>friend constexpr bool operator!=(const sentinel&amp; x, const iterator&amp; y);</del>
  };
}</code></pre>
<pre><code>constexpr explicit sentinel(filter_view&amp; parent);</code></pre>
<em>Effects</em>: Initializes <code class="language-cpp">end_</code> with <code class="language-cpp">ranges::end(parent)</code>.
<pre><code>constexpr sentinel_t&lt;V&gt; base() const;</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return end_;</code>
<pre><code>friend constexpr bool operator==(const iterator&amp; x, const sentinel&amp; y);</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return x.current_ == y.end_;</code>
<pre><code><del>friend constexpr bool operator==(const sentinel&amp; x, const iterator&amp; y);</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return y == x;</code></del>
<pre><code><del>friend constexpr bool operator!=(const iterator&amp; x, const sentinel&amp; y);</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x == y);</code></del>
<pre><code><del>friend constexpr bool operator!=(const sentinel&amp; x, const iterator&amp; y);</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(y == x);</code></del></p>
</blockquote>
<p>Change 24.7.5.3 [range.transform.iterator]:</p>
<blockquote><pre><code>namespace std::ranges {
  template&lt;class V, class F&gt;
  template&lt;bool Const&gt;
  class transform_view&lt;V, F&gt;::iterator {
    [...]
    friend constexpr bool operator==(const iterator& x, const iterator& y)
      requires EqualityComparable&lt;iterator_t&lt;Base&gt;&gt;;
    <del>friend constexpr bool operator!=(const iterator& x, const iterator& y)</del>
    <del>  requires EqualityComparable&lt;iterator_t&lt;Base&gt;&gt;;</del>

    friend constexpr bool operator&lt;(const iterator& x, const iterator& y)
      requires RandomAccessRange&lt;Base&gt;;
    friend constexpr bool operator&gt;(const iterator& x, const iterator& y)
      requires RandomAccessRange&lt;Base&gt;;
    friend constexpr bool operator&lt;=(const iterator& x, const iterator& y)
      requires RandomAccessRange&lt;Base&gt;;
    friend constexpr bool operator&gt;=(const iterator& x, const iterator& y)
      requires RandomAccessRange&lt;Base&gt;;
    <ins>friend constexpr compare_three_way_result_t&lt;iterator_t&lt;Base&gt;&gt; operator&lt;=&gt;(const iterator& x, const iterator& y)</ins>
    <ins>  requires RandomAccessRange&lt;Base&gt;; && ThreeWayComparable&lt;iterator_t&lt;Base&gt;&gt;</ins>
    [...]
  };
}</code></pre></blockquote>

<p>Change 24.7.5.3 [range.transform.iterator], paragraphs 13-18:</p>
<blockquote>
<p><pre><code>friend constexpr bool operator==(const iterator&amp; x, const iterator&amp; y)
  requires EqualityComparable&lt;iterator_t&lt;Base&gt;&gt;;</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return x.current_ == y.current_;</code>
<pre><code><del>friend constexpr bool operator!=(const iterator&amp; x, const iterator&amp; y)
  requires EqualityComparable&lt;iterator_t&lt;Base&gt;&gt;;</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x == y);</code></del>
<pre><code>friend constexpr bool operator&lt;(const iterator&amp; x, const iterator&amp; y)
  requires RandomAccessRange&lt;Base&gt;;</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return x.current_ &lt; y.current_;</code><br />
[...]<br />
<pre><code>friend constexpr bool operator&gt;=(const iterator&amp; x, const iterator&amp; y)
  requires RandomAccessRange&lt;Base&gt;;</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x &lt; y);</code>
<pre><code><ins>friend constexpr compare_three_way_result_t&lt;iterator_t&lt;Base&gt;&gt; operator&lt;=&gt;(const iterator&amp; x, const iterator&amp; y)
  requires RandomAccessRange&lt;Base&gt;; &amp;&amp; ThreeWayComparable&lt;iterator_t&lt;Base&gt;&gt;</ins></code></pre>
<ins><em>Effects</em>: Equivalent to: <code class="language-cpp">return x.current_ &lt;=&gt; y.current_;</code></ins></p>
</blockquote>
<p>Remove obsolete equality operators from 24.7.5.4 [range.transform.sentinel]:</p>
<blockquote><pre><code>namespace std::ranges {
  template&lt;class V, class F&gt;
  template&lt;bool Const&gt;
  class transform_view&lt;V, F&gt;::sentinel {
    [...]
    friend constexpr bool operator==(const iterator&lt;Const&gt;& x, const sentinel& y);
    <del>friend constexpr bool operator==(const sentinel& x, const iterator&lt;Const&gt;& y);</del>
    <del>friend constexpr bool operator!=(const iterator&lt;Const&gt;& x, const sentinel& y);</del>
    <del>friend constexpr bool operator!=(const sentinel& x, const iterator&lt;Const&gt;& y);</del>
    [...]
  };
}</code></pre></blockquote>

<p>and from 24.7.5.4 [range.transform.sentinel], paragraphs 4-7:</p>
<blockquote>
<p><pre><code>friend constexpr bool operator==(const iterator&lt;Const&gt;&amp; x, const sentinel&amp; y);</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return x.current_ == y.end_</code>;
<pre><code><del>friend constexpr bool operator==(const sentinel&amp; x, const iterator&lt;Const&gt;&amp; y);</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return y == x;</code></del>
<pre><code><del>friend constexpr bool operator!=(const iterator&lt;Const&gt;&amp; x, const sentinel&amp; y);</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x == y);</code></del>
<pre><code><del>friend constexpr bool operator!=(const sentinel&amp; x, const iterator&lt;Const&gt;&amp; y);</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(y == x);</code></del></p>
</blockquote>
<p>Remove obsolete equality operators from 24.7.6.3 [range.take.sentinel]:</p>
<blockquote><pre><code>namespace std::ranges {
  template&lt;class V&gt;
  template&lt;bool Const&gt;
  class take_view&lt;V&gt;::sentinel {
  private:
    using Base = conditional_t&lt;Const, const V, V&gt;;      // exposition only
    using CI = counted_iterator&lt;iterator_t&lt;Base&gt;&gt;;      // exposition only
    sentinel_t&lt;Base&gt; end_ = sentinel_t&lt;Base&gt;();         // exposition only
  public:
    [...]
    <del>friend constexpr bool operator==(const sentinel& x, const CI& y);</del>
    friend constexpr bool operator==(const CI& y, const sentinel& x);
    <del>friend constexpr bool operator!=(const sentinel& x, const CI& y);</del>
    <del>friend constexpr bool operator!=(const CI& y, const sentinel& x);</del>
  };
}</code></pre></blockquote>

<p>and from 24.7.6.3 [range.take.sentinel] paragraphs 4-5:</p>
<blockquote>
<p><pre><code><del>friend constexpr bool operator==(const sentinel&amp; x, const CI&amp; y);</del>
friend constexpr bool operator==(const CI&amp; y, const sentinel&amp; x);</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return y.count() == 0 || y.base() == x.end_;</code>
<pre><code><del>friend constexpr bool operator!=(const sentinel&amp; x, const CI&amp; y);
friend constexpr bool operator!=(const CI&amp; y, const sentinel&amp; x);</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x == y);</code></del></p>
</blockquote>
<p>Remove obsolete <code class="language-cpp">operator!=</code> from 24.7.7.3 [range.join.iterator]:</p>
<blockquote><pre><code>namespace std::ranges {
template&lt;class V&gt;
  template&lt;bool Const&gt;
  struct join_view&lt;V&gt;::iterator {
    [...]
    friend constexpr bool operator==(const iterator& x, const iterator& y)
      requires ref_is_glvalue && EqualityComparable&lt;iterator_t&lt;Base&gt;&gt; &&
               EqualityComparable&lt;iterator_t&lt;iter_reference_t&lt;iterator_t&lt;Base&gt;&gt;&gt;&gt;;

<del>    friend constexpr bool operator!=(const iterator& x, const iterator& y)
      requires ref_is_glvalue && EqualityComparable&lt;iterator_t&lt;Base&gt;&gt; &&
               EqualityComparable&lt;iterator_t&lt;iter_reference_t&lt;iterator_t&lt;Base&gt;&gt;&gt;&gt;;</del>
    [...]
  };
}</code></pre></blockquote>

<p>and from 24.7.7.3 [range.join.iterator] paragraph 17:</p>
<blockquote>
<p><pre><code>friend constexpr bool operator==(const iterator&amp; x, const iterator&amp; y)
  requires ref_is_glvalue &amp;&amp; EqualityComparable&lt;iterator_t&lt;Base&gt;&gt; &amp;&amp;
           EqualityComparable&lt;iterator_t&lt;iter_reference_t&lt;iterator_t&lt;Base&gt;&gt;&gt;&gt;;</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return x.outer_ == y.outer_ &amp;&amp; x.inner_ == y.inner_;</code>
<pre><code><del>friend constexpr bool operator!=(const iterator&amp; x, const iterator&amp; y)
  requires ref_is_glvalue &amp;&amp; EqualityComparable&lt;iterator_t&lt;Base&gt;&gt; &amp;&amp;
           EqualityComparable&lt;iterator_t&lt;iter_reference_t&lt;iterator_t&lt;Base&gt;&gt;&gt;&gt;;</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x == y);</code></del></p>
</blockquote>
<p>Remove obsolete equality operators from 24.7.7.4 [range.join.sentinel]:</p>
<blockquote><pre><code>namespace std::ranges {
  template&lt;class V&gt;
  template&lt;bool Const&gt;
  struct join_view&lt;V&gt;::sentinel {
    [...]
    friend constexpr bool operator==(const iterator&lt;Const&gt;& x, const sentinel& y);
    <del>friend constexpr bool operator==(const sentinel& x, const iterator&lt;Const&gt;& y);</del>
    <del>friend constexpr bool operator!=(const iterator&lt;Const&gt;& x, const sentinel& y);</del>
    <del>friend constexpr bool operator!=(const sentinel& x, const iterator&lt;Const&gt;& y);</del>
  };
}</code></pre></blockquote>

<p>and from 24.7.7.4 [range.join.sentinel] paragraphs 3-6:</p>
<blockquote>
<p><pre><code>friend constexpr bool operator==(const iterator&lt;Const&gt;&amp; x, const sentinel&amp; y);</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return x.outer_ == y.end_;</code>
<pre><code><del>friend constexpr bool operator==(const sentinel&amp; x, const iterator&lt;Const&gt;&amp; y);</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return y == x;</code></del>
<pre><code><del>friend constexpr bool operator!=(const iterator&lt;Const&gt;&amp; x, const sentinel&amp; y);</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x == y);</code></del>
<pre><code><del>friend constexpr bool operator!=(const sentinel&amp; x, const iterator&lt;Const&gt;&amp; y);</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(y == x);</code></del></p>
</blockquote>
<p>Remove obsolete equality operators from 24.7.8.3 [range.split.outer]:</p>
<blockquote><pre><code>namespace std::ranges {
  template&lt;class V, class Pattern&gt;
  template&lt;bool Const&gt;
  struct split_view&lt;V, Pattern&gt;::outer_iterator {
    [...]
    friend constexpr bool operator==(const outer_iterator& x, const outer_iterator& y)
      requires ForwardRange&lt;Base&gt;;
    <del>friend constexpr bool operator!=(const outer_iterator& x, const outer_iterator& y)</del>
    <del>  requires ForwardRange&lt;Base&gt;;</del>

    friend constexpr bool operator==(const outer_iterator& x, default_sentinel_t);
    <del>friend constexpr bool operator==(default_sentinel_t, const outer_iterator& x);</del>
    <del>friend constexpr bool operator!=(const outer_iterator& x, default_sentinel_t y);</del>
    <del>friend constexpr bool operator!=(default_sentinel_t y, const outer_iterator& x);</del>
  };
}</code></pre></blockquote>

<p>and from 24.7.8.3 [range.split.outer] paragraphs 7-10:</p>
<blockquote>
<p><pre><code>friend constexpr bool operator==(const outer_iterator&amp; x, const outer_iterator&amp; y)
  requires ForwardRange&lt;Base&gt;;</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return x.current_ == y.current_;</code>
<pre><code><del>friend constexpr bool operator!=(const outer_iterator&amp; x, const outer_iterator&amp; y)
  requires ForwardRange&lt;Base&gt;;</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x == y);</code></del>
<pre><code>friend constexpr bool operator==(const outer_iterator&amp; x, default_sentinel_t);
<del>friend constexpr bool operator==(default_sentinel_t, const outer_iterator&amp; x);</del></code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return x.current_ == ranges::end(x.parent_-&gt;base_);</code>
<pre><code><del>friend constexpr bool operator!=(const outer_iterator&amp; x, default_sentinel_t y);
friend constexpr bool operator!=(default_sentinel_t y, const outer_iterator&amp; x);</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x == y);</code></del></p>
</blockquote>
<p>Remove obsolete equality operators from 24.7.8.5 [range.split.inner]:</p>
<blockquote><pre><code>namespace std::ranges {
  template&lt;class V, class Pattern&gt;
  template&lt;bool Const&gt;
  struct split_view&lt;V, Pattern&gt;::inner_iterator {
    [...]
    friend constexpr bool operator==(const inner_iterator& x, const inner_iterator& y)
      requires ForwardRange&lt;Base&gt;;
    <del>friend constexpr bool operator!=(const inner_iterator& x, const inner_iterator& y)</del>
    <del>  requires ForwardRange&lt;Base&gt;;</del>

    friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t);
    <del>friend constexpr bool operator==(default_sentinel_t, const inner_iterator& x);</del>
    <del>friend constexpr bool operator!=(const inner_iterator& x, default_sentinel_t y);</del>
    <del>friend constexpr bool operator!=(default_sentinel_t y, const inner_iterator& x);</del>
    [...]
  };
}</code></pre></blockquote>

<p>and from 24.7.8.5 [ranges.split.inner] paragraphs 4-7:</p>
<blockquote>
<p><pre><code>friend constexpr bool operator==(const inner_iterator&amp; x, const inner_iterator&amp; y)
  requires ForwardRange&lt;Base&gt;;</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return x.i_.current_ == y.i_.current_;</code>
<pre><code><del>friend constexpr bool operator!=(const inner_iterator&amp; x, const inner_iterator&amp; y)
  requires ForwardRange&lt;Base&gt;;</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x == y);</code></del>
<pre><code>friend constexpr bool operator==(const inner_iterator&amp; x, default_sentinel_t);
<del>friend constexpr bool operator==(default_sentinel_t, const inner_iterator&amp; x);</del></code></pre>
<em>Effects</em>: Equivalent to:
<pre><code>auto cur = x.i_.current;
auto end = ranges::end(x.i_.parent_-&gt;base_);
if (cur == end) return true;
auto [pcur, pend] = subrange{x.i_.parent_-&gt;pattern_};
if (pcur == pend) return x.incremented_;
do {
  if (<em>cur != </em>pcur) return false;
  if (++pcur == pend) return true;
} while (++cur != end);
return false;</code></pre></p>
<p><pre><code><del>friend constexpr bool operator!=(const inner_iterator&amp; x, default_sentinel_t y);
friend constexpr bool operator!=(default_sentinel_t y, const inner_iterator&amp; x);</del></code></pre>
<del><em>Effects</em>: Equivalent to: <code class="language-cpp">return !(x == y);</code></del></p>
</blockquote>
<h3 id="clause-25-algorithms-library">4.10. Clause 25: Algorithms library<a class="self-link" href="#clause-25-algorithms-library"></a></h3>
<p>Change 25.4 [algorithm.syn]:</p>
<blockquote><pre><code>namespace std {
  [...]
  // [alg.3way], three-way comparison algorithms
  <del>template&lt;class T, class U&gt;</del>
  <del>  constexpr auto compare_3way(const T& a, const U& b);</del>
  template&lt;class InputIterator1, class InputIterator2, class Cmp&gt;
    constexpr auto
      <del>lexicographical_compare_3way(InputIterator1 b1, InputIterator1 e1,</del>
      <ins>lexicographical_compare_three_way(InputIterator1 b1, InputIterator1 e1,</ins>
                                   InputIterator2 b2, InputIterator2 e2,
                                   Cmp comp)
        -&gt; common_comparison_category_t&lt;decltype(comp(*b1, *b2)), strong_ordering&gt;;
  template&lt;class InputIterator1, class InputIterator2&gt;
    constexpr auto
      <del>lexicographical_compare_3way(InputIterator1 b1, InputIterator1 e1,</del>
      <ins>lexicographical_compare_three_way(InputIterator1 b1, InputIterator1 e1,</ins>
                                   InputIterator2 b2, InputIterator2 e2);
  [...]
}</code></pre></blockquote>

<p>Change 25.7.11 [alg.3way]:</p>
<blockquote><del><code>template&lt;class T, class U&gt; constexpr auto compare_3way(const T& a, const U& b);</code>

<p><i>Effects</i>: Compares two values and produces a result of the strongest applicable comparison category type:
<ul>
<li> Returns a <=> b if that expression is well-formed.
<li> Otherwise, if the expressions a == b and a < b are each well-formed and convertible to bool, returns strong_ordering​::​equal when a == b is true, otherwise returns strong_ordering​::​less when a < b is true, and otherwise returns strong_ordering​::​greater.
<li> Otherwise, if the expression a == b is well-formed and convertible to bool, returns strong_equality​::​equal when a == b is true, and otherwise returns strong_equality​::​nonequal.
<li>Otherwise, the function is defined as deleted.
</ul></del></blockquote>

<p>Change 25.7.11 [alg.3way] paragraph 2:</p>
<blockquote><pre><code>template&lt;class InputIterator1, class InputIterator2, class Cmp&gt;
  constexpr auto
    <del>lexicographical_compare_3way(InputIterator1 b1, InputIterator1 e1,</del>
    <ins>lexicographical_compare_three_way(InputIterator1 b1, InputIterator1 e1,</ins>
                                 InputIterator2 b2, InputIterator2 e2,
                                 Cmp comp);</code></pre></blockquote>

<p>Change 25.7.11 [alg.3way] paragraph 4:</p>
<blockquote><pre><code>template&lt;class InputIterator1, class InputIterator2&gt;
  constexpr auto
    <del>lexicographical_compare_3way(InputIterator1 b1, InputIterator1 e1,</del>
    <ins>lexicographical_compare_three_way(InputIterator1 b1, InputIterator1 e1,</ins>
                                 InputIterator2 b2, InputIterator2 e2);</code></pre>

<i>Effects</i>: Equivalent to:
<pre><code><del>return lexicographical_compare_3way(b1, e1, b2, e2,</del>
                                    <del>[](const auto& t, const auto& u) {</del>
                                    <del>  return compare_3way(t, u);</del>
                                    <del>});</del>
<ins>return lexicographical_compare_three_way(b1, e1, b2, e2, compare_three_way());</ins></code></pre>             
</blockquote>

<h3 id="clause-26-numerics-library">4.11. Clause 26: Numerics library<a class="self-link" href="#clause-26-numerics-library"></a></h3>
<p>Remove obsolete equality operators from 26.4.1 [complex.syn]:</p>
<blockquote><pre><code>namespace std {
  // [complex], class template complex
  template&lt;class T&gt; class complex;

  // [complex.special], specializations
  template&lt;&gt; class complex&lt;float&gt;;
  template&lt;&gt; class complex&lt;double&gt;;
  template&lt;&gt; class complex&lt;long double&gt;;

  [...]

  template&lt;class T&gt; constexpr bool operator==(const complex&lt;T&gt;&, const complex&lt;T&gt;&);
  template&lt;class T&gt; constexpr bool operator==(const complex&lt;T&gt;&, const T&);
  <del>template&lt;class T&gt; constexpr bool operator==(const T&, const complex&lt;T&gt;&);</del>

  <del>template&lt;class T&gt; constexpr bool operator!=(const complex&lt;T&gt;&, const complex&lt;T&gt;&);</del>
  <del>template&lt;class T&gt; constexpr bool operator!=(const complex&lt;T&gt;&, const T&);</del>
  <del>template&lt;class T&gt; constexpr bool operator!=(const T&, const complex&lt;T&gt;&);</del>

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

<p>and in 26.4.6 [complex.ops]:</p>
<blockquote>
<p><pre><code>template&lt;class T&gt; constexpr bool operator==(const complex&lt;T&gt;&amp; lhs, const complex&lt;T&gt;&amp; rhs);
template&lt;class T&gt; constexpr bool operator==(const complex&lt;T&gt;&amp; lhs, const T&amp; rhs);
<del>template&lt;class T&gt; constexpr bool operator==(const T&amp; lhs, const complex&lt;T&gt;&amp; rhs);</del></code></pre>
<em>Returns</em>: <code class="language-cpp">lhs.real() == rhs.real() &amp;&amp; lhs.imag() == rhs.imag()</code>.<br />
<em>Remarks</em>: The imaginary part is assumed to be <code class="language-cpp">T()</code>, or <code class="language-cpp">0.0</code>, for the <code class="language-cpp">T</code> arguments.
<pre><code><del>template&lt;class T&gt; constexpr bool operator!=(const complex&lt;T&gt;&amp; lhs, const complex&lt;T&gt;&amp; rhs);
template&lt;class T&gt; constexpr bool operator!=(const complex&lt;T&gt;&amp; lhs, const T&amp; rhs);
template&lt;class T&gt; constexpr bool operator!=(const T&amp; lhs, const complex&lt;T&gt;&amp; rhs);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">rhs.real() != lhs.real() || rhs.imag() != lhs.imag()</code>.</del></p>
</blockquote>
<p>Add <code class="language-cpp">operator==</code> to <code class="language-cpp">std::slice</code> in 26.7.4.1 [class.slice.overview]:</p>
<blockquote><pre><code>namespace std {
  class slice {
  public:
    slice();
    slice(size_t, size_t, size_t);

    size_t start() const;
    size_t size() const;
    size_t stride() const;

    <ins>friend bool operator==(const slice& x, const slice& y);</ins>
  };
}</code></pre></blockquote>

<p>and add a new subclause "Operators" after 26.7.4.3 [slice.access]:</p>
<blockquote>
<p><pre><code><ins>friend bool operator==(const slice&amp; x, const slice&amp; y);</ins></code></pre>
<ins><em>Effects</em>: Equivalent to <pre><code>return x.start() == y.start() &amp;&amp;
  x.size() == y.size() &amp;&amp;
  x.stride() == y.stride();</code></pre></ins></p>
</blockquote>
<h3 id="clause-27-time-library">4.12. Clause 27: Time library<a class="self-link" href="#clause-27-time-library"></a></h3>
<p>Change 27.2 [time.syn]:</p>
<blockquote><pre><code>namespace std {
  namespace chrono {
    [...]
<del>    // [time.duration.comparisons], duration comparisons
    template&lt;class Rep1, class Period1, class Rep2, class Period2&gt;
      constexpr bool operator==(const duration&lt;Rep1, Period1&gt;& lhs,
                                const duration&lt;Rep2, Period2&gt;& rhs);
    template&lt;class Rep1, class Period1, class Rep2, class Period2&gt;
      constexpr bool operator!=(const duration&lt;Rep1, Period1&gt;& lhs,
                                const duration&lt;Rep2, Period2&gt;& rhs);
    template&lt;class Rep1, class Period1, class Rep2, class Period2&gt;
      constexpr bool operator&lt; (const duration&lt;Rep1, Period1&gt;& lhs,
                                const duration&lt;Rep2, Period2&gt;& rhs);
    template&lt;class Rep1, class Period1, class Rep2, class Period2&gt;
      constexpr bool operator&gt; (const duration&lt;Rep1, Period1&gt;& lhs,
                                const duration&lt;Rep2, Period2&gt;& rhs);
    template&lt;class Rep1, class Period1, class Rep2, class Period2&gt;
      constexpr bool operator&lt;=(const duration&lt;Rep1, Period1&gt;& lhs,
                                const duration&lt;Rep2, Period2&gt;& rhs);
    template&lt;class Rep1, class Period1, class Rep2, class Period2&gt;
      constexpr bool operator&gt;=(const duration&lt;Rep1, Period1&gt;& lhs,
                                const duration&lt;Rep2, Period2&gt;& rhs);</del>

    [...]

<del>    // [time.point.comparisons], time_point comparisons
    template&lt;class Clock, class Duration1, class Duration2&gt;
       constexpr bool operator==(const time_point&lt;Clock, Duration1&gt;& lhs,
                                 const time_point&lt;Clock, Duration2&gt;& rhs);
    template&lt;class Clock, class Duration1, class Duration2&gt;
       constexpr bool operator!=(const time_point&lt;Clock, Duration1&gt;& lhs,
                                 const time_point&lt;Clock, Duration2&gt;& rhs);
    template&lt;class Clock, class Duration1, class Duration2&gt;
       constexpr bool operator&lt; (const time_point&lt;Clock, Duration1&gt;& lhs,
                                 const time_point&lt;Clock, Duration2&gt;& rhs);
    template&lt;class Clock, class Duration1, class Duration2&gt;
       constexpr bool operator&gt; (const time_point&lt;Clock, Duration1&gt;& lhs,
                                 const time_point&lt;Clock, Duration2&gt;& rhs);
    template&lt;class Clock, class Duration1, class Duration2&gt;
       constexpr bool operator&lt;=(const time_point&lt;Clock, Duration1&gt;& lhs,
                                 const time_point&lt;Clock, Duration2&gt;& rhs);
    template&lt;class Clock, class Duration1, class Duration2&gt;
       constexpr bool operator&gt;=(const time_point&lt;Clock, Duration1&gt;& lhs,
                                 const time_point&lt;Clock, Duration2&gt;& rhs);</del>

    [...]

    // [time.cal.day], class day
    class day;

<del>    constexpr bool operator==(const day& x, const day& y) noexcept;
    constexpr bool operator!=(const day& x, const day& y) noexcept;
    constexpr bool operator< (const day& x, const day& y) noexcept;
    constexpr bool operator> (const day& x, const day& y) noexcept;
    constexpr bool operator<=(const day& x, const day& y) noexcept;
    constexpr bool operator>=(const day& x, const day& y) noexcept;</del>

    [...]

    // [time.cal.month], class month
    class month;

<del>    constexpr bool operator==(const month& x, const month& y) noexcept;
    constexpr bool operator!=(const month& x, const month& y) noexcept;
    constexpr bool operator< (const month& x, const month& y) noexcept;
    constexpr bool operator> (const month& x, const month& y) noexcept;
    constexpr bool operator<=(const month& x, const month& y) noexcept;
    constexpr bool operator>=(const month& x, const month& y) noexcept;</del>

    [...]

    // [time.cal.year], class year
    class year;

<del>    constexpr bool operator==(const year& x, const year& y) noexcept;
    constexpr bool operator!=(const year& x, const year& y) noexcept;
    constexpr bool operator< (const year& x, const year& y) noexcept;
    constexpr bool operator> (const year& x, const year& y) noexcept;
    constexpr bool operator<=(const year& x, const year& y) noexcept;
    constexpr bool operator>=(const year& x, const year& y) noexcept;</del>

    [...]

    // [time.cal.wd], class weekday
    class weekday;

<del>    constexpr bool operator==(const weekday& x, const weekday& y) noexcept;
    constexpr bool operator!=(const weekday& x, const weekday& y) noexcept;</del>

    [...]

    // [time.cal.wdidx], class weekday_indexed
    class weekday_indexed;

<del>    constexpr bool operator==(const weekday_indexed& x, const weekday_indexed& y) noexcept;
    constexpr bool operator!=(const weekday_indexed& x, const weekday_indexed& y) noexcept;</del>

    [...]

    // [time.cal.wdlast], class weekday_last
    class weekday_last;

<del>    constexpr bool operator==(const weekday_last& x, const weekday_last& y) noexcept;
    constexpr bool operator!=(const weekday_last& x, const weekday_last& y) noexcept;</del>

    [...]

    // [time.cal.md], class month_day
    class month_day;

<del>    constexpr bool operator==(const month_day& x, const month_day& y) noexcept;
    constexpr bool operator!=(const month_day& x, const month_day& y) noexcept;
    constexpr bool operator< (const month_day& x, const month_day& y) noexcept;
    constexpr bool operator> (const month_day& x, const month_day& y) noexcept;
    constexpr bool operator<=(const month_day& x, const month_day& y) noexcept;
    constexpr bool operator>=(const month_day& x, const month_day& y) noexcept;</del>

    [...]

    // [time.cal.mdlast], class month_day_last
    class month_day_last;

<del>    constexpr bool operator==(const month_day_last& x, const month_day_last& y) noexcept;
    constexpr bool operator!=(const month_day_last& x, const month_day_last& y) noexcept;
    constexpr bool operator< (const month_day_last& x, const month_day_last& y) noexcept;
    constexpr bool operator> (const month_day_last& x, const month_day_last& y) noexcept;
    constexpr bool operator<=(const month_day_last& x, const month_day_last& y) noexcept;
    constexpr bool operator>=(const month_day_last& x, const month_day_last& y) noexcept;</del>

    [...]

    // [time.cal.mwd], class month_weekday
    class month_weekday;

<del>    constexpr bool operator==(const month_weekday& x, const month_weekday& y) noexcept;
    constexpr bool operator!=(const month_weekday& x, const month_weekday& y) noexcept;</del>

    [...]

    // [time.cal.mwdlast], class month_weekday_last
    class month_weekday_last;

<del>    constexpr bool operator==(const month_weekday_last& x, const month_weekday_last& y) noexcept;
    constexpr bool operator!=(const month_weekday_last& x, const month_weekday_last& y) noexcept;</del>

    [...]

    // [time.cal.ym], class year_month
    class year_month;

<del>    constexpr bool operator==(const year_month& x, const year_month& y) noexcept;
    constexpr bool operator!=(const year_month& x, const year_month& y) noexcept;
    constexpr bool operator< (const year_month& x, const year_month& y) noexcept;
    constexpr bool operator> (const year_month& x, const year_month& y) noexcept;
    constexpr bool operator<=(const year_month& x, const year_month& y) noexcept;
    constexpr bool operator>=(const year_month& x, const year_month& y) noexcept;</del>

    [...]

    // [time.cal.ymd], class year_month_day
    class year_month_day;

<del>    constexpr bool operator==(const year_month_day& x, const year_month_day& y) noexcept;
    constexpr bool operator!=(const year_month_day& x, const year_month_day& y) noexcept;
    constexpr bool operator< (const year_month_day& x, const year_month_day& y) noexcept;
    constexpr bool operator> (const year_month_day& x, const year_month_day& y) noexcept;
    constexpr bool operator<=(const year_month_day& x, const year_month_day& y) noexcept;
    constexpr bool operator>=(const year_month_day& x, const year_month_day& y) noexcept;</del>

    [...]

    // [time.cal.ymdlast], class year_month_day_last
    class year_month_day_last;

<del>    constexpr bool operator==(const year_month_day_last& x,
                              const year_month_day_last& y) noexcept;
    constexpr bool operator!=(const year_month_day_last& x,
                              const year_month_day_last& y) noexcept;
    constexpr bool operator< (const year_month_day_last& x,
                              const year_month_day_last& y) noexcept;
    constexpr bool operator> (const year_month_day_last& x,
                              const year_month_day_last& y) noexcept;
    constexpr bool operator<=(const year_month_day_last& x,
                              const year_month_day_last& y) noexcept;
    constexpr bool operator>=(const year_month_day_last& x,
                              const year_month_day_last& y) noexcept;</del>

    [...]

    // [time.cal.ymwd], class year_month_weekday
    class year_month_weekday;

<del>    constexpr bool operator==(const year_month_weekday& x,
                              const year_month_weekday& y) noexcept;
    constexpr bool operator!=(const year_month_weekday& x,
                              const year_month_weekday& y) noexcept;</del>

    [...]

    // [time.cal.ymwdlast], class year_month_weekday_last
    class year_month_weekday_last;

<del>    constexpr bool operator==(const year_month_weekday_last& x,
                              const year_month_weekday_last& y) noexcept;
    constexpr bool operator!=(const year_month_weekday_last& x,
                              const year_month_weekday_last& y) noexcept;</del>

    [...]

    // [time.zone.timezone], class time_zone
    enum class choose {earliest, latest};
    class time_zone;

<del>    bool operator==(const time_zone& x, const time_zone& y) noexcept;
    bool operator!=(const time_zone& x, const time_zone& y) noexcept;

    bool operator<(const time_zone& x, const time_zone& y) noexcept;
    bool operator>(const time_zone& x, const time_zone& y) noexcept;
    bool operator<=(const time_zone& x, const time_zone& y) noexcept;
    bool operator>=(const time_zone& x, const time_zone& y) noexcept;</del>    
    [...]

    // [time.zone.zonedtime], class template zoned_time
    template&lt;class Duration, class TimeZonePtr = const time_zone*&gt; class zoned_time;

    using zoned_seconds = zoned_time<seconds>;

<del>    template&lt;class Duration1, class Duration2, class TimeZonePtr&gt;
      bool operator==(const zoned_time&lt;Duration1, TimeZonePtr&gt;& x,
                      const zoned_time&lt;Duration2, TimeZonePtr&gt;& y);

    template&lt;class Duration1, class Duration2, class TimeZonePtr&gt;
      bool operator!=(const zoned_time&lt;Duration1, TimeZonePtr&gt;& x,
                      const zoned_time&lt;Duration2, TimeZonePtr&gt;& y);</del>

    [...]

    // [time.zone.leap], leap second support
    class leap;

<del>    bool operator==(const leap& x, const leap& y);
    bool operator!=(const leap& x, const leap& y);
    bool operator&lt; (const leap& x, const leap& y);
    bool operator&gt; (const leap& x, const leap& y);
    bool operator&lt;=(const leap& x, const leap& y);
    bool operator&gt;=(const leap& x, const leap& y);</del>

<Del>    template&lt;class Duration&gt;
      bool operator==(const leap& x, const sys_time&lt;Duration&gt;& y);
    template&lt;class Duration&gt;
      bool operator==(const sys_time&lt;Duration&gt;& x, const leap& y);
    template&lt;class Duration&gt;
      bool operator!=(const leap& x, const sys_time&lt;Duration&gt;& y);
    template&lt;class Duration&gt;
      bool operator!=(const sys_time&lt;Duration&gt;& x, const leap& y);
    template&lt;class Duration&gt;
      bool operator&lt; (const leap& x, const sys_time&lt;Duration&gt;& y);
    template&lt;class Duration&gt;
      bool operator&lt; (const sys_time&lt;Duration&gt;& x, const leap& y);
    template&lt;class Duration&gt;
      bool operator&gt; (const leap& x, const sys_time&lt;Duration&gt;& y);
    template&lt;class Duration&gt;
      bool operator&gt; (const sys_time&lt;Duration&gt;& x, const leap& y);
    template&lt;class Duration&gt;
      bool operator&lt;=(const leap& x, const sys_time&lt;Duration&gt;& y);
    template&lt;class Duration&gt;
      bool operator&lt;=(const sys_time&lt;Duration&gt;& x, const leap& y);
    template&lt;class Duration&gt;
      bool operator&gt;=(const leap& x, const sys_time&lt;Duration&gt;& y);
    template&lt;class Duration&gt;
      bool operator&gt;=(const sys_time&lt;Duration&gt;& x, const leap& y);</del>

    // [time.zone.link], class link
    class link;

<del>    bool operator==(const link& x, const link& y);
    bool operator!=(const link& x, const link& y);
    bool operator&lt; (const link& x, const link& y);
    bool operator&gt; (const link& x, const link& y);
    bool operator&lt;=(const link& x, const link& y);
    bool operator&gt;=(const link& x, const link& y);</del>
  }
}</code></pre></blockquote>

<p>Change 27.5 [time.duration]:</p>
<blockquote><pre><code>namespace std::chrono {
  template&lt;class Rep, class Period = ratio&lt;1&gt;&gt;
  class duration {
  public:
    using rep    = Rep;
    using period = typename Period::type;

  private:
    rep rep_;       // exposition only

  public:
    [...]
<ins>    // [time.duration.comparisons], duration comparisons
    template&lt;class Rep2, class Period2&gt;
      friend constexpr bool operator==(const duration& lhs, const duration&lt;Rep2, Period2&gt;& rhs);
    template&lt;class Rep2, class Period2&gt;
      friend constexpr bool operator&lt;(const duration& lhs, const duration&lt;Rep2, Period2&gt;& rhs);
    template&lt;class Rep2, class Period2&gt;
      friend constexpr bool operator&gt;(const duration& lhs, const duration&lt;Rep2, Period2&gt;& rhs);
    template&lt;class Rep2, class Period2&gt;
      friend constexpr bool operator&lt;=(const duration& lhs, const duration&lt;Rep2, Period2&gt;& rhs);
    template&lt;class Rep2, class Period2&gt;
      friend constexpr bool operator&gt;=(const duration& lhs, const duration&lt;Rep2, Period2&gt;& rhs);
    template&lt;class Rep2, class Period2&gt; requires <i>see below</i>
      friend constexpr <i>see below</i> operator&lt;=&gt;(const duration& lhs, const duration&lt;Rep2, Period2&gt;& rhs);</ins>
  };
}</code></pre></blockquote>

<p>Change 27.5.6 [time.duration.comparisons]:</p>
<p>In the function descriptions that follow, <code class="language-cpp">CT</code> represents <code class="language-cpp">common_type_t&lt;A, B&gt;</code>, where <code class="language-cpp">A</code> and <code class="language-cpp">B</code> are the types of the two arguments to the function.</p>
<blockquote>
<p><pre><code>template&lt;<del>class Rep1, class Period1, </del>class Rep2, class Period2&gt;
  <ins>friend</ins> constexpr bool operator==(const duration<del>&lt;Rep1, Period1&gt;</del>&amp; lhs,
                            const duration&lt;Rep2, Period2&gt;&amp; rhs);</code></pre>
<em>Returns</em>: <code class="language-cpp">CT(lhs).count() == CT(rhs).count()</code>.
<pre><code><del>template&lt;class Rep1, class Period1, class Rep2, class Period2&gt;
  constepxr bool operator!=(const duration&lt;Rep1, Period1&gt;&amp; lhs,
                            const duration&lt;Rep2, Period2&gt;&amp; rhs);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(lhs == rhs)</code>.</del>
<pre><code>template&lt;<del>class Rep1, class Period1, </del>class Rep2, class Period2&gt;
  <ins>friend</ins> constexpr bool operator&lt;(const duration<del>&lt;Rep1, Period1&gt;</del>&amp; lhs,
                           const duration&lt;Rep2, Period2&gt;&amp; rhs);</code></pre>
<em>Returns</em>: <code class="language-cpp">CT(lhs).count() &lt; CT(rhs).count()</code>.
<pre><code>template&lt;<del>class Rep1, class Period1, </del>class Rep2, class Period2&gt;
  <ins>friend</ins> constexpr bool operator&gt;(const duration<del>&lt;Rep1, Period1&gt;</del>&amp; lhs,
                           const duration&lt;Rep2, Period2&gt;&amp; rhs);</code></pre>
<em>Returns</em>: <code class="language-cpp">rhs &lt; lhs</code>.
<pre><code>template&lt;<del>class Rep1, class Period1, </del>class Rep2, class Period2&gt;
  <ins>friend</ins> constexpr bool operator&lt;=(const duration<del>&lt;Rep1, Period1&gt;</del>&amp; lhs,
                            const duration&lt;Rep2, Period2&gt;&amp; rhs);</code></pre>
<em>Returns</em>: <code class="language-cpp">!(rhs &lt; lhs)</code>.
<pre><code>template&lt;<del>class Rep1, class Period1, </del>class Rep2, class Period2&gt;
  <ins>friend</ins> constexpr bool operator&gt;=(const duration<del>&lt;Rep1, Period1&gt;</del>&amp; lhs,
                            const duration&lt;Rep2, Period2&gt;&amp; rhs);</code></pre>
<em>Returns</em>: <code class="language-cpp">!(lhs &lt; rhs)</code>.
<pre><code><ins>template&lt;class Rep2, class Period2&gt; requires ThreeWayComparable&lt;typename CT::rep&gt;
  friend constexpr compare_three_way_result_t&lt;typename CT::rep&gt; operator&lt;=&gt;(const duration&amp; lhs,
                                                              const duration&lt;Rep2, Period2&gt;&amp; rhs);</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">CT(lhs).count() &lt;=&gt; CT(rhs).count()</code></ins></p>
</blockquote>
<p>Change 27.6 [time.point]:</p>
<blockquote><pre><code>namespace std::chrono {
  template&lt;class Clock, class Duration = typename Clock::duration&gt;
  class time_point {
  public:
    [...]

<ins>    // [time.point.comparisons], time_point comparisons
    template&lt;class Duration2&gt;
      friend constexpr bool operator==(const time_point& lhs, const time_point&lt;Clock, Duration2&gt;& rhs);
    template&lt;class Duration2&gt;
      friend constexpr bool operator&lt;(const time_point& lhs, const time_point&lt;Clock, Duration2&gt;& rhs);
    template&lt;class Duration2&gt;
      friend constexpr bool operator&gt;(const time_point& lhs, const time_point&lt;Clock, Duration2&gt;& rhs);
    template&lt;class Duration2&gt;
      friend constexpr bool operator&lt;=(const time_point& lhs, const time_point&lt;Clock, Duration2&gt;& rhs);
    template&lt;class Duration2&gt;
      friend constexpr bool operator&gt;=(const time_point& lhs, const time_point&lt;Clock, Duration2&gt;& rhs);
    template&lt;ThreeWayComparableWith&lt;Duration&gt; Duration2&gt;
      friend constexpr compare_three_way_result_t&lt;Duration, Duration2&gt;
        operator&lt;=&gt;(const time_point& lhs, const time_point&lt;Clock, Duration2&gt;& rhs);</ins>
  };
}</code></pre></blockquote>

<p>Change 27.6.6 [time.point.comparisons]:</p>
<blockquote>
<p><pre><code>template&lt;<del>class Clock, class Duration1, </del>class Duration2&gt;
  <ins>friend </ins>constexpr bool operator==(const time_point<del>&lt;Clock, Duration1&gt;</del>&amp; lhs,
                            const time_point&lt;Clock, Duration2&gt;&amp; rhs);</code></pre>
<em>Returns</em>: <code class="language-cpp">lhs.time_since_epoch() == rhs.time_since_epoch()</code>.
<pre><code><del>template&lt;class Clock, class Duration1, class Duration2&gt;
  constexpr bool operator!=(const time_point&lt;Clock, Duration1&gt;&amp; lhs,
                            const time_point&lt;Clock, Duration2&gt;&amp; rhs);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(lhs == rhs)</code>.</del>
<pre><code>template&lt;<del>class Clock, class Duration1, </del>class Duration2&gt;
  <ins>friend </ins>constexpr bool operator&lt;(const time_point<del>&lt;Clock, Duration1&gt;</del>&amp; lhs,
                           const time_point&lt;Clock, Duration2&gt;&amp; rhs);</code></pre>
<em>Returns</em>: <code class="language-cpp">lhs.time_since_epoch() &lt; rhs.time_since_epoch()</code>.
<pre><code>template&lt;<del>class Clock, class Duration1, </del>class Duration2&gt;
  <ins>friend </ins>constexpr bool operator&gt;(const time_point<del>&lt;Clock, Duration1&gt;</del>&amp; lhs,
                           const time_point&lt;Clock, Duration2&gt;&amp; rhs);</code></pre>
<em>Returns</em>: <code class="language-cpp">rhs &lt; lhs</code>.
<pre><code>template&lt;<del>class Clock, class Duration1, </del>class Duration2&gt;
  <ins>friend </ins>constexpr bool operator&lt;=(const time_point<del>&lt;Clock, Duration1&gt;</del>&amp; lhs,
                            const time_point&lt;Clock, Duration2&gt;&amp; rhs);</code></pre>
<em>Returns</em>: <code class="language-cpp">!(rhs &lt; lhs)</code>.
<pre><code>template&lt;<del>class Clock, class Duration1, </del>class Duration2&gt;
  <ins>friend </ins>constexpr bool operator&gt;=(const time_point<del>&lt;Clock, Duration1&gt;</del>&amp; lhs,
                            const time_point&lt;Clock, Duration2&gt;&amp; rhs);</code></pre>
<em>Returns</em>: <code class="language-cpp">!(lhs &lt; rhs)</code>.
<pre><code><ins>template&lt;ThreeWayComparableWith&lt;Duration&gt; Duration2&gt;
  friend constexpr compare_three_way_result_t&lt;Duration, Duration2&gt;
    operator&lt;=&gt;(const time_point&amp; lhs, const time_point&lt;Clock, Duration2&gt;&amp; rhs);</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">lhs.time_since_epoch() &lt;=&gt; rhs.time_since_epoch()</code>.</ins></p>
</blockquote>
<p>Change 27.8.3.1 [time.cal.day.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class day {
    unsigned char d_;           // exposition only
  public:
    [...]

    <ins>friend constexpr bool operator==(const day& x, const day& y) noexcept;</ins>
    <ins>friend constexpr strong_ordering operator<=>(const day& x, const day& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.8.3.3 [time.cal.day.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const day&amp; x, const day&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">unsigned{x} == unsigned{y}</code>.
<pre><code><del>constexpr bool operator&lt;(const day&amp; x, const day&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">unsigned{x} &lt; unsigned{y}</code>.</del>
<pre><code><ins>friend constexpr strong_ordering operator&lt;=&gt;(const day&amp; x, const day&amp; y) noexcept;</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">unsigned{x} &lt;=&gt; unsigned{y}</code>.</ins></p>
</blockquote>
<p>Change 27.8.4.1 [time.cal.month.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class month {
    unsigned char m_;           // exposition only
  public:
    [...]

    <ins>friend constexpr bool operator==(const month& x, const month& y) noexcept;</ins>
    <ins>friend constexpr strong_ordering operator<=>(const month& x, const month& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.8.4.3 [time.cal.month.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const month&amp; x, const month&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">unsigned{x} == unsigned{y}</code>.
<pre><code><del>constexpr bool operator&lt;(const month&amp; x, const month&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">unsigned{x} &lt; unsigned{y}</code>.</del>
<pre><code><ins>friend constexpr strong_ordering operator&lt;=&gt;(const month&amp; x, const month&amp; y) noexcept;</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">unsigned{x} &lt;=&gt; unsigned{y}</code>.</ins></p>
</blockquote>
<p>Change 27.8.5.1 [time.cal.year.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class year {
    short y_;           // exposition only
  public:
    [...]

    <ins>friend constexpr bool operator==(const year& x, const year& y) noexcept;</ins>
    <ins>friend constexpr strong_ordering operator<=>(const year& x, const year& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.8.5.3 [time.cal.year.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const year&amp; x, const year&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">int{x} == int{y}</code>.
<pre><code><del>constexpr bool operator&lt;(const year&amp; x, const year&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">int{x} &lt; int{y}</code>.</del>
<pre><code><ins>friend constexpr strong_ordering operator&lt;=&gt;(const year&amp; x, const year&amp; y) noexcept;</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">int{x} &lt;=&gt; int{y}</code>.</ins></p>
</blockquote>
<p>Change 27.8.6.1 [time.cal.wd.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class weekday {
    unsigned char wd_;           // exposition only
  public:
    [...]

    <ins>friend constexpr bool operator==(const weekday& x, const weekday& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.8.6.3 [time.cal.wd.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const weekday&amp; x, const weekday&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">unsigned{x} == unsigned{y}</code>.</p>
</blockquote>
<p>Change 27.8.7.1 [time.cal.wdidx.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class weekday_indexed {
    chrono::weekday  wd_;       // exposition only
    unsigned char    index_;    // exposition only
  public:
    [...]

    <ins>friend constexpr bool operator==(const weekday_indexed& x, const weekday_indexed& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.8.7.3 [time.cal.wdidx.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const weekday_indexed&amp; x, const weekday_indexed&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">x.weekday() == y.weekday() &amp;&amp; x.index() == y.index()</code>.</p>
</blockquote>
<p>Change 27.8.8.1 [time.cal.wdlast.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class weekday_last {
    chrono::weekday wd_;                // exposition only
  public:
    [...]

    <ins>friend constexpr bool operator==(const weekday_last& x, const weekday_last& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.8.8.3 [time.cal.wdlast.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const weekday_last&amp; x, const weekday_last&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">x.weekday() == y.weekday()</code>.</p>
</blockquote>
<p>Change 27.8.9.1 [time.cal.md.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class month_day {
    chrono::month m_;           // exposition only
    chrono::day   d_;           // exposition only
  public:
    [...]

    <ins>friend constexpr bool operator==(const month_day& x, const month_day& y) noexcept;</ins>
    <ins>friend constexpr strong_ordering operator<=>(const month_day& x, const month_day& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.8.9.3 [time.cal.md.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const month_day&amp; x, const month_day&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">x.month() == y.month() &amp;&amp; x.day() == y.day()</code>.
<pre><code><del>constexpr bool operator&lt;(const month_day&amp; x, const month_day&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: If <code class="language-cpp">x.month() &lt; y.month()</code> returns <code class="language-cpp">true</code>. Otherwise, if <code class="language-cpp">x.month() &gt; y.month()</code> returns <code class="language-cpp">false</code>. Otherwise, returns <code class="language-cpp">x.day() &lt; y.day()</code>.</del>
<pre><code><ins>friend constexpr strong_ordering operator&lt;=&gt;(const month_day&amp; x, const month_day&amp; y) noexcept;</ins></code></pre>
<ins><em>Returns</em>: Let <code class="language-cpp">c</code> be <code class="language-cpp">x.month() &lt;=&gt; y.month()</code>. If <code class="language-cpp">c != 0</code> returns <code class="language-cpp">c</code>. Otherwise, returns <code class="language-cpp">x.day() &lt;=&gt; y.day()</code>.</ins></p>
</blockquote>
<p>Change 27.8.10.1 [time.cal.mdlast.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class month_day_last {
    chrono::month m_;           // exposition only
  public:
    [...]

    <ins>friend constexpr bool operator==(const month_day_last& x, const month_day_last& y) noexcept;</ins>
    <ins>friend constexpr strong_ordering operator<=>(const month_day_last& x, const month_day_last& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.8.10.3 [time.cal.mdlast.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const month_day_last&amp; x, const month_day_last&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">x.month() == y.month()</code>.
<pre><code><del>constexpr bool operator&lt;(const month_day_last&amp; x, const month_day_last&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">x.month() &lt; y.month()</code>.</del>
<pre><code><ins>friend constexpr strong_ordering operator&lt;=&gt;(const month_day_last&amp; x, const month_day_last&amp; y) noexcept;</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">x.month() &lt;=&gt; y.month()</code>.</ins></p>
</blockquote>
<p>Change 27.8.11.1 [time.cal.mwd.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class month_weekday {
    chrono::month           m_;         // exposition only
    chrono::weekday_indexed wdi_;       // exposition only
  public:
    [...]

    <ins>friend constexpr bool operator==(const month_weekday& x, const month_weekday& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.8.11.3 [time.cal.mwd.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const month_weekday&amp; x, const month_weekday&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">x.month() == y.month() &amp;&amp; x.weekday_indexed() == y.weekday_indexed()</code>.</p>
</blockquote>
<p>Change 27.8.12.1 [time.cal.mwdlast.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class month_weekday_last {
    chrono::month        m_;    // exposition only
    chrono::weekday_last wdl_;  // exposition only
  public:
    [...]

    <ins>friend constexpr bool operator==(const month_weekday_last& x, const month_weekday_last& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.8.12.3 [time.cal.mwdlast.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const month_weekday_last&amp; x, const month_weekday_last&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">x.month() == y.month() &amp;&amp; x.weekday_last() == y.weekday_last()</code>.</p>
</blockquote>
<p>Change 27.8.13.1 [time.cal.ym.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class year_month {
    chrono::year  y_;           // exposition only
    chrono::month m_;           // exposition only
  public:
    [...]

    <ins>friend constexpr bool operator==(const year_month& x, const year_month& y) noexcept;</ins>
    <ins>friend constexpr strong_ordering operator<=>(const year_month& x, const year_month& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.8.13.3 [time.cal.ym.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const year_month&amp; x, const year_month&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">x.year() == y.year() &amp;&amp; x.month() == y.month()</code>.
<pre><code><del>constexpr bool operator&lt;(const year_month&amp; x, const year_month&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: If <code class="language-cpp">x.year() &lt; y.year()</code> returns <code class="language-cpp">true</code>. Otherwise, if <code class="language-cpp">x.year() &gt; y.year()</code> returns <code class="language-cpp">false</code>. Otherwise, returns <code class="language-cpp">x.month() &lt; y.month()</code>.</del>
<pre><code><ins>friend constexpr strong_ordering operator&lt;=&gt;(const year_month&amp; x, const year_month&amp; y) noexcept;</ins></code></pre>
<ins><em>Returns</em>: Let <code class="language-cpp">c</code> be <code class="language-cpp">x.year() &lt;=&gt; y.year()</code>. If <code class="language-cpp">c != 0</code> returns <code class="language-cpp">c</code>. Otherwise, returns <code class="language-cpp">x.month() &lt;=&gt; y.month()</code>.</ins></p>
</blockquote>
<p>Change 27.8.14.1 [time.cal.ymd.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class year_month_day {
    chrono::year  y_;           // exposition only
    chrono::month m_;           // exposition only
    chrono::day   d_;           // exposition only
  public:
    [...]

    <ins>friend constexpr bool operator==(const year_month_day& x, const year_month_day& y) noexcept;</ins>
    <ins>friend constexpr strong_ordering operator<=>(const year_month_day& x, const year_month_day& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.8.14.3 [time.cal.ymd.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const year_month_day&amp; x, const year_month_day&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">x.year() == y.year() &amp;&amp; x.month() == y.month() &amp;&amp; x.day() == y.day()</code>.
<pre><code><del>constexpr bool operator&lt;(const year_month_day&amp; x, const year_month_day&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: If x.year() &lt; y.year(), returns true. Otherwise, if x.year() &gt; y.year(), returns false. Otherwise, if x.month() &lt; y.month(), returns true. Otherwise, if x.month() &gt; y.month(), returns false. Otherwise, returns x.day() &lt; y.day().</del>
<pre><code><ins>friend constexpr strong_ordering operator&lt;=&gt;(const year_month_day&amp; x, const year_month_day&amp; y) noexcept;</ins></code></pre>
<ins><em>Returns</em>: Let <code class="language-cpp">c</code> be <code class="language-cpp">x.year() &lt;=&gt; y.year()</code>. If <code class="language-cpp">c != 0</code> returns <code class="language-cpp">c</code>. Let <code class="language-cpp">c2</code> be <code class="language-cpp">x.month() &lt;=&gt; y.month()</code>. If <code class="language-cpp">c2 != 0</code> returns <code class="language-cpp">c2</code>. Otherwise, returns <code class="language-cpp">x.day() &lt;=&gt; y.day()</code>.</ins></p>
</blockquote>
<p>Change 27.8.15.1 [time.cal.ymdlast.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class year_month_day_last {
    chrono::year           y_;          // exposition only
    chrono::month_day_last mdl_;        // exposition only
  public:
    [...]

    <ins>friend constexpr bool operator==(const year_month_day_last& x, const year_month_day_last& y) noexcept;</ins>
    <ins>friend constexpr strong_ordering operator<=>(const year_month_day_last& x, const year_month_day_last& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.8.15.3 [time.cal.ymdlast.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const year_month_day_last&amp; x, const year_month_day_last&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">x.year() == y.year() &amp;&amp; x.month_day_last() == y.month_day_last()</code>.
<pre><code><del>constexpr bool operator&lt;(const year_month_day_last&amp; x, const year_month_day_last&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: If <code class="language-cpp">x.year() &lt; y.year()</code> returns <code class="language-cpp">true</code>. Otherwise, if <code class="language-cpp">x.year() &gt; y.year()</code> returns <code class="language-cpp">false</code>. Otherwise, returns <code class="language-cpp">x.month_day_last() &lt; y.month_day_last()</code>.</del>
<pre><code><ins>friend constexpr strong_ordering operator&lt;=&gt;(const year_month_day_last&amp; x, const year_month_day_last&amp; y) noexcept;</ins></code></pre>
<ins><em>Returns</em>: Let <code class="language-cpp">c</code> be <code class="language-cpp">x.year() &lt;=&gt; y.year()</code>. If <code class="language-cpp">c != 0</code> returns <code class="language-cpp">c</code>. Otherwise, returns <code class="language-cpp">x.month_day_last() &lt;=&gt; y.month_day_last()</code>.</ins></p>
</blockquote>
<p>Change 27.8.16.1 [time.cal.ymwd.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class year_month_weekday {
    chrono::year            y_;         // exposition only
    chrono::month           m_;         // exposition only
    chrono::weekday_indexed wdi_;       // exposition only
  public:
    [...]

    <ins>friend constexpr bool operator==(const year_month_weekday& x, const year_month_weekday& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.8.16.3 [time.cal.ymwd.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const year_month_weekday&amp; x, const year_month_weekday&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">x.year() == y.year() &amp;&amp; x.month() == y.month() &amp;&amp; x.weekday_indexed() == y.weekday_indexed()</code>.</p>
</blockquote>
<p>Change 27.8.17.1 [time.cal.ymwdlast.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class year_month_weekday_last {
    chrono::year         y_;    // exposition only
    chrono::month        m_;    // exposition only
    chrono::weekday_last wdl_;  // exposition only
  public:
    [...]

    <ins>friend constexpr bool operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.8.17.3 [time.cal.ymwdlast.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const year_month_weekday_last&amp; x, const year_month_weekday_last&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">x.year() == y.year() &amp;&amp; x.month() == y.month() &amp;&amp; x.weekday_last() == y.weekday_last()</code>.</p>
</blockquote>
<p>Change 27.10.5.1 [time.zone.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class time_zone {
  public:
    [...]

    template&lt;class Duration&gt;
      local_time&lt;common_type_t&lt;Duration, seconds&gt;&gt;
        to_local(const sys_time&lt;Duration&gt;& tp) const;

    <ins>friend bool operator==(const time_zone& x, const time_zone& y) noexcept;</ins>
    <ins>friend strong_ordering operator<=>(const time_zone& x, const time_zone& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.10.5.3 [time.zone.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>bool operator==(const time_zone&amp; x, const time_zone&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">x.name() == y.name()</code>.
<pre><code><del>bool operator&lt;(const time_zone&amp; x, const time_zone&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">x.name() &lt; y.name()</code>.</del>
<pre><code><ins>strong_ordering operator&lt;=&gt;(const time_zone&amp; x, const time_zone&amp; y) noexcept;</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">x.name() &lt;=&gt; y.name()</code>.</ins></p>
</blockquote>
<p>Change 27.10.7.1 [time.zone.zonedtime.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  template<class Duration, class TimeZonePtr = const time_zone*>
  class zoned_time {
  public:
    [...]
    sys_time<duration>   get_sys_time()   const;
    sys_info             get_info()       const;

    <ins>template&lt;class Duration2&gt;</ins>
    <ins>  friend bool operator==(const zoned_time& x, const zoned_time&lt;Duration2, TimeZonePtr&gt;& y);</ins>
  };
  [...]
}</code></pre></blockquote>

<p>Change 27.10.7.4 [time.zone.zonedtime.nonmembers]:</p>
<blockquote>
<p><pre><code>template&lt;<del>class Duration1, </del>class Duration2<del>, class TimeZonePtr</del>&gt;
  <ins>friend  </ins>bool operator==(const zoned_time<del>&lt;Duration1, TimeZonePtr&gt;</del>&amp; x,
                  const zoned_time&lt;Duration2, TimeZonePtr&gt;&amp; y);</code></pre>
<em>Returns</em>: <code class="language-cpp">x.zone_ == y.zone_ &amp;&amp; x.tp_ == y.tp_</code>.
<pre><code><del>template&lt;class Duration1, class Duration2, class TimeZonePtr&gt;
  bool operator!=(const zoned_time&lt;Duration1, TimeZonePtr&gt;&amp; x,
                  const zoned_time&lt;Duration2, TimeZonePtr&gt;&amp; y);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(x == y)</code>.</del></p>
</blockquote>
<p>Change 27.10.8.1 [time.zone.leap.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class leap {
  public:
    leap(const leap&)            = default;
    leap& operator=(const leap&) = default;

    // unspecified additional constructors

    constexpr sys_seconds date() const noexcept;

    <ins>friend constexpr bool operator==(const leap& x, const leap& y) noexcept;</ins>
    <ins>friend constexpr strong_ordering operator&lt;=&gt;(const leap& x, const leap& y) noexcept;</ins>

    <ins>template&lt;class Duration&gt;</ins>
    <ins>  friend constexpr bool operator==(const leap& x, const sys_time&lt;Duration&gt;& y) noexcept;</ins>
    <ins>template&lt;class Duration&gt;</ins>
    <ins>  friend constexpr strong_ordering operator&lt;=&gt;(const leap& x, const sys_time&lt;Duration&gt;& y)</ins> noexcept;      
  };
}</code></pre></blockquote>

<p>Change 27.10.8.3 [time.zone.leap.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>constexpr bool operator==(const leap&amp; x, const leap&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">x.date() == y.date()</code>.
<pre><code><del>constexpr bool operator&lt;(const leap&amp; x, const leap&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">x.date() &lt; y.date()</code>.</del>
<pre><code><ins>friend constexpr strong_ordering operator&lt;=&gt;(const leap&amp; x, const leap&amp; y) noexcept;</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">x.date() &lt;=&gt; y.date()</code>.</ins>
<pre><code>template&lt;class Duration&gt;
  <ins>friend </ins>constexpr bool operator==(const leap&amp; x, const sys_time&lt;Duration&gt;&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">x.date() == y</code>.
<pre><code><ins>template&lt;class Duration&gt;
  friend constexpr strong_ordering operator&lt;=&gt;(const leap&amp; x, const sys_time&lt;Duration&gt;&amp; y) noexcept;</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">x.date() &lt;=&gt; y</code>.</ins>
<pre><code><del>template&lt;class Duration&gt;
  constexpr bool operator==(const sys_time&lt;Duration&gt;&amp; x, const leap&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">y == x</code>.</del>
<pre><code><del>template&lt;class Duration&gt;
  constexpr bool operator!=(const leap&amp; x, const sys_time&lt;Duration&gt;&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(x == y)</code>.</del>
<pre><code><del>template&lt;class Duration&gt;
  constexpr bool operator!=(const sys_time&lt;Duration&gt;&amp; x, const leap&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(x == y)</code>.</del>
<pre><code><del>template&lt;class Duration&gt;
  constexpr bool operator&lt;(const leap&amp; x, const sys_time&lt;Duration&gt;&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">x.date() &lt; y</code>.</del>
<pre><code><del>template&lt;class Duration&gt;
  constexpr bool operator&lt;(const sys_time&lt;Duration&gt;&amp; x, const leap&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">x &lt; y.date()</code>.</del>
<pre><code><del>template&lt;class Duration&gt;
  constexpr bool operator&gt;(const leap&amp; x, const sys_time&lt;Duration&gt;&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">y &lt; x</code>.</del>
<pre><code><del>template&lt;class Duration&gt;
  constexpr bool operator&gt;(const sys_time&lt;Duration&gt;&amp; x, const leap&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">y &lt; x</code>.</del>
<pre><code><del>template&lt;class Duration&gt;
  constexpr bool operator&lt;=(const leap&amp; x, const sys_time&lt;Duration&gt;&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(y &lt; x)</code>.</del>
<pre><code><del>template&lt;class Duration&gt;
  constexpr bool operator&lt;=(const sys_time&lt;Duration&gt;&amp; x, const leap&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(y &lt; x)</code>.</del>
<pre><code><del>template&lt;class Duration&gt;
  constexpr bool operator&gt;=(const leap&amp; x, const sys_time&lt;Duration&gt;&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(x &lt; y)</code>.</del>
<pre><code><del>template&lt;class Duration&gt;
  constexpr bool operator&gt;=(const sys_time&lt;Duration&gt;&amp; x, const leap&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(x &lt; y)</code>.</del></p>
</blockquote>
<p>Change 27.10.9.1 [time.zone.link.overview]:</p>
<blockquote><pre><code>namespace std::chrono {
  class link {
  public:
    link(link&&)            = default;
    link& operator=(link&&) = default;

    // unspecified additional constructors

    string_view name()   const noexcept;
    string_view target() const noexcept;

    <ins>friend bool operator==(const link& x, const link& y) noexcept;</ins>
    <ins>friend strong_ordering operator<=>(const link& x, const link& y) noexcept;</ins>
  };
}</code></pre></blockquote>

<p>Change 27.10.9.3 [time.zone.link.nonmembers]:</p>
<blockquote>
<p><pre><code><ins>friend </ins>bool operator==(const link&amp; x, const link&amp; y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">x.name() == y.name()</code>.
<pre><code><del>bool operator&lt;(const link&amp; x, const link&amp; y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">x.name() &lt; y.name()</code>.</del>
<pre><code><ins>strong_ordering operator&lt;=&gt;(const link&amp; x, const link&amp; y) noexcept;</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">x.name() &lt;=&gt; y.name()</code>.</ins></p>
</blockquote>
<h3 id="clause-28-localization-library">4.13. Clause 28: Localization library<a class="self-link" href="#clause-28-localization-library"></a></h3>
<p>Change 28.3.1 [locale]:</p>
<blockquote><pre><code>namespace std {
  class locale {
  public:
    [...]
    // locale operations
    basic_string<char> name() const;

    bool operator==(const locale& other) const;
    <del>bool operator!=(const locale& other) const;</del>
    [...]
  };
}</code></pre></blockquote>

<p>Change 28.3.1.4 [locale.operators]:</p>
<blockquote>
<p><pre><code>bool operator==(const locale&amp; other) const;</code></pre>
<em>Returns</em>: <code class="language-cpp">true</code> if both arguments are the same locale, or one is a copy of the other, or each has a name and the names are identical; <code class="language-cpp">false</code> otherwise.
<pre><code><del>bool operator!=(const locale&amp; other) const;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(*this == other)</code>.</del></p>
</blockquote>
<h3 id="clause-29-inputoutput-library">4.14. Clause 29: Input/output library<a class="self-link" href="#clause-29-inputoutput-library"></a></h3>
<p>Change 29.11.5 [fs.filesystem.syn]:</p>
<blockquote><pre><code>namespace std::filesystem {
  [...]
  // [fs.class.file_status], file status
  class file_status;

  struct space_info {
    uintmax_t capacity;
    uintmax_t free;
    uintmax_t available;

    <ins>friend bool operator==(const space_info&, const space_info&) = default;</ins>
  };
  [...]
}</code></pre></blockquote>

<p>Change 29.11.7 [fs.class.path]:</p>
<blockquote><pre><code>namespace std::filesystem {
  class path {
  public:
    [...]
    // [fs.path.nonmember], non-member operators
    friend bool operator==(const path& lhs, const path& rhs) noexcept;
    <del>friend bool operator!=(const path& lhs, const path& rhs) noexcept;</del>
    <del>friend bool operator< (const path& lhs, const path& rhs) noexcept;</del>
    <del>friend bool operator<=(const path& lhs, const path& rhs) noexcept;</del>
    <del>friend bool operator> (const path& lhs, const path& rhs) noexcept;</del>
    <del>friend bool operator>=(const path& lhs, const path& rhs) noexcept;</del>
    <ins>friend weak_ordering operator<=>(const path& lhs, const path& rhs) noexcept;</ins>
    [...]
  };
}</code></pre></blockquote>

<p>Change 29.11.7.7 [fs.path.nonmember], paragraphs 5-10:</p>
<blockquote>
<p><pre><code><del>friend bool operator!=(const path&amp; lhs, const path&amp; rhs) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(lhs == rhs)</code>.</del>
<pre><code><del>friend bool operator&lt; (const path&amp; lhs, const path&amp; rhs) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">lhs.compare(rhs) &lt; 0</code>.</del>
<pre><code><del>friend bool operator&lt;=(const path&amp; lhs, const path&amp; rhs) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(rhs &lt; lhs)</code>.</del>
<pre><code><del>friend bool operator&gt; (const path&amp; lhs, const path&amp; rhs) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">rhs &lt; lhs</code>.</del>
<pre><code><del>friend bool operator&gt;=(const path&amp; lhs, const path&amp; rhs) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(lhs &lt; rhs)</code>.</del>
<pre><code><ins>friend weak_ordering operator&lt;=&gt;(const path&amp; lhs, const path&amp; rhs) noexcept;</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">lhs.compare(rhs) &lt;=&gt; 0</code>.</ins>
<pre><code>friend path operator/ (const path&amp; lhs, const path&amp; rhs);</code></pre>
<em>Effects</em>: Equivalent to: <code class="language-cpp">return path(lhs) /= rhs;</code></p>
</blockquote>
<p>Change 29.11.10 [fs.class.file_status]:</p>
<blockquote><pre><code>namespace std::filesystem {
  class file_status {
  public:
    // [fs.file_status.cons], constructors and destructor
    file_status() noexcept : file_status(file_type::none) {}
    explicit file_status(file_type ft,
                         perms prms = perms::unknown) noexcept;
    file_status(const file_status&) noexcept = default;
    file_status(file_status&&) noexcept = default;
    ~file_status();

    // assignments
    file_status& operator=(const file_status&) noexcept = default;
    file_status& operator=(file_status&&) noexcept = default;

    // [fs.file_status.mods], modifiers
    void       type(file_type ft) noexcept;
    void       permissions(perms prms) noexcept;

    // [fs.file_status.obs], observers
    file_type  type() const noexcept;
    perms      permissions() const noexcept;

    <ins>friend bool operator==(const file_status& lhs, const file_status& rhs) noexcept</ins>
    <ins>{ return lhs.type() == rhs.type() && lhs.permissions() == rhs.permissions(); }</ins>
  };
}</code></pre></blockquote>

<p>Change 29.11.11 [fs.class.directory_entry]:</p>
<blockquote><pre><code>namespace std::filesystem {
  class directory_entry {
  public:
    [...]
    bool operator==(const directory_entry& rhs) const noexcept;
    <del>bool operator!=(const directory_entry& rhs) const noexcept;</del>
    <del>bool operator< (const directory_entry& rhs) const noexcept;</del>
    <del>bool operator> (const directory_entry& rhs) const noexcept;</del>
    <del>bool operator<=(const directory_entry& rhs) const noexcept;</del>
    <del>bool operator>=(const directory_entry& rhs) const noexcept;</del>
    <ins>weak_ordering operator<=>(const directory_entry& rhs) const noexcept;</ins>

  private:
    filesystem::path pathobject;     // exposition only
    friend class directory_iterator; // exposition only
  };
}</code></pre></blockquote>

<p>Change 29.11.11.3 [fs.dir.entry.obs], paragraphs 31-36:</p>
<blockquote>
<p><pre><code>bool operator==(const directory_entry&amp; rhs) const noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">pathobject == rhs.pathobject</code>.
<pre><code><del>bool operator!=(const directory_entry&amp; rhs) const noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">pathobject != rhs.pathobject</code>.</del>
<pre><code><del>bool operator&lt; (const directory_entry&amp; rhs) const noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">pathobject &lt; rhs.pathobject</code>.</del>
<pre><code><del>bool operator&gt; (const directory_entry&amp; rhs) const noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">pathobject &gt; rhs.pathobject</code>.</del>
<pre><code><del>bool operator&lt;=(const directory_entry&amp; rhs) const noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">pathobject &lt;= rhs.pathobject</code>.</del>
<pre><code><del>bool operator&gt;=(const directory_entry&amp; rhs) const noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">pathobject &gt;= rhs.pathobject</code>.</del>
<pre><code><ins>weak_ordering operator&lt;=&gt;(const directory_entry&amp; rhs) const noexcept;</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">pathobject &lt;=&gt; rhs.pathobject</code>.</ins></p>
</blockquote>
<h3 id="clause-30-regular-expressions-library">4.15. Clause 30: Regular expressions library<a class="self-link" href="#clause-30-regular-expressions-library"></a></h3>
<p>Change 30.4 [re.syn]:</p>
<blockquote><pre><code>#include &lt;initializer_list&gt;

namespace std {
  [...]
  // [re.submatch], class template sub_match
  template&lt;class BidirectionalIterator&gt;
    class sub_match;

  using csub_match  = sub_match&lt;const char*&gt;;
  using wcsub_match = sub_match&lt;const wchar_t*&gt;;
  using ssub_match  = sub_match&lt;string::const_iterator&gt;;
  using wssub_match = sub_match&lt;wstring::const_iterator&gt;;

<del>  // [re.submatch.op], sub_match non-member operators
  template&lt;class BiIter&gt;
    bool operator==(const sub_match&lt;BiIter&gt;& lhs, const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter&gt;
    bool operator!=(const sub_match&lt;BiIter&gt;& lhs, const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter&gt;
    bool operator&lt;(const sub_match&lt;BiIter&gt;& lhs, const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter&gt;
    bool operator&gt;(const sub_match&lt;BiIter&gt;& lhs, const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter&gt;
    bool operator&lt;=(const sub_match&lt;BiIter&gt;& lhs, const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter&gt;
    bool operator&gt;=(const sub_match&lt;BiIter&gt;& lhs, const sub_match&lt;BiIter&gt;& rhs);

  template&lt;class BiIter, class ST, class SA&gt;
    bool operator==(
      const basic_string&lt;typename iterator_traits&lt;BiIter&gt;::value_type, ST, SA&gt;& lhs,
      const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter, class ST, class SA&gt;
    bool operator!=(
      const basic_string&lt;typename iterator_traits&lt;BiIter&gt;::value_type, ST, SA&gt;& lhs,
      const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter, class ST, class SA&gt;
    bool operator&lt;(
      const basic_string&lt;typename iterator_traits&lt;BiIter&gt;::value_type, ST, SA&gt;& lhs,
      const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter, class ST, class SA&gt;
    bool operator&gt;(
      const basic_string&lt;typename iterator_traits&lt;BiIter&gt;::value_type, ST, SA&gt;& lhs,
      const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter, class ST, class SA&gt;
    bool operator&lt;=(
      const basic_string&lt;typename iterator_traits&lt;BiIter&gt;::value_type, ST, SA&gt;& lhs,
      const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter, class ST, class SA&gt;
    bool operator&gt;=(
      const basic_string&lt;typename iterator_traits&lt;BiIter&gt;::value_type, ST, SA&gt;& lhs,
      const sub_match&lt;BiIter&gt;& rhs);

  template&lt;class BiIter, class ST, class SA&gt;
    bool operator==(
      const sub_match&lt;BiIter&gt;& lhs,
      const basic_string&lt;typename iterator_traits&lt;BiIter&gt;::value_type, ST, SA&gt;& rhs);
  template&lt;class BiIter, class ST, class SA&gt;
    bool operator!=(
      const sub_match&lt;BiIter&gt;& lhs,
      const basic_string&lt;typename iterator_traits&lt;BiIter&gt;::value_type, ST, SA&gt;& rhs);
  template&lt;class BiIter, class ST, class SA&gt;
    bool operator&lt;(
      const sub_match&lt;BiIter&gt;& lhs,
      const basic_string&lt;typename iterator_traits&lt;BiIter&gt;::value_type, ST, SA&gt;& rhs);
  template&lt;class BiIter, class ST, class SA&gt;
    bool operator&gt;(
      const sub_match&lt;BiIter&gt;& lhs,
      const basic_string&lt;typename iterator_traits&lt;BiIter&gt;::value_type, ST, SA&gt;& rhs);
  template&lt;class BiIter, class ST, class SA&gt;
    bool operator&lt;=(
      const sub_match&lt;BiIter&gt;& lhs,
      const basic_string&lt;typename iterator_traits&lt;BiIter&gt;::value_type, ST, SA&gt;& rhs);
  template&lt;class BiIter, class ST, class SA&gt;
    bool operator&gt;=(
      const sub_match&lt;BiIter&gt;& lhs,
      const basic_string&lt;typename iterator_traits&lt;BiIter&gt;::value_type, ST, SA&gt;& rhs);

  template&lt;class BiIter&gt;
    bool operator==(const typename iterator_traits&lt;BiIter&gt;::value_type* lhs,
                    const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter&gt;
    bool operator!=(const typename iterator_traits&lt;BiIter&gt;::value_type* lhs,
                    const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter&gt;
    bool operator&lt;(const typename iterator_traits&lt;BiIter&gt;::value_type* lhs,
                   const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter&gt;
    bool operator&gt;(const typename iterator_traits&lt;BiIter&gt;::value_type* lhs,
                   const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter&gt;
    bool operator&lt;=(const typename iterator_traits&lt;BiIter&gt;::value_type* lhs,
                    const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter&gt;
    bool operator&gt;=(const typename iterator_traits&lt;BiIter&gt;::value_type* lhs,
                    const sub_match&lt;BiIter&gt;& rhs);

  template&lt;class BiIter&gt;
    bool operator==(const sub_match&lt;BiIter&gt;& lhs,
                    const typename iterator_traits&lt;BiIter&gt;::value_type* rhs);
  template&lt;class BiIter&gt;
    bool operator!=(const sub_match&lt;BiIter&gt;& lhs,
                    const typename iterator_traits&lt;BiIter&gt;::value_type* rhs);
  template&lt;class BiIter&gt;
    bool operator&lt;(const sub_match&lt;BiIter&gt;& lhs,
                   const typename iterator_traits&lt;BiIter&gt;::value_type* rhs);
  template&lt;class BiIter&gt;
    bool operator&gt;(const sub_match&lt;BiIter&gt;& lhs,
                   const typename iterator_traits&lt;BiIter&gt;::value_type* rhs);
  template&lt;class BiIter&gt;
    bool operator&lt;=(const sub_match&lt;BiIter&gt;& lhs,
                    const typename iterator_traits&lt;BiIter&gt;::value_type* rhs);
  template&lt;class BiIter&gt;
    bool operator&gt;=(const sub_match&lt;BiIter&gt;& lhs,
                    const typename iterator_traits&lt;BiIter&gt;::value_type* rhs);

  template&lt;class BiIter&gt;
    bool operator==(const typename iterator_traits&lt;BiIter&gt;::value_type& lhs,
                    const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter&gt;
    bool operator!=(const typename iterator_traits&lt;BiIter&gt;::value_type& lhs,
                    const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter&gt;
    bool operator&lt;(const typename iterator_traits&lt;BiIter&gt;::value_type& lhs,
                   const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter&gt;
    bool operator&gt;(const typename iterator_traits&lt;BiIter&gt;::value_type& lhs,
                   const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter&gt;
    bool operator&lt;=(const typename iterator_traits&lt;BiIter&gt;::value_type& lhs,
                    const sub_match&lt;BiIter&gt;& rhs);
  template&lt;class BiIter&gt;
    bool operator&gt;=(const typename iterator_traits&lt;BiIter&gt;::value_type& lhs,
                    const sub_match&lt;BiIter&gt;& rhs);

  template&lt;class BiIter&gt;
    bool operator==(const sub_match&lt;BiIter&gt;& lhs,
                    const typename iterator_traits&lt;BiIter&gt;::value_type& rhs);
  template&lt;class BiIter&gt;
    bool operator!=(const sub_match&lt;BiIter&gt;& lhs,
                    const typename iterator_traits&lt;BiIter&gt;::value_type& rhs);
  template&lt;class BiIter&gt;
    bool operator&lt;(const sub_match&lt;BiIter&gt;& lhs,
                   const typename iterator_traits&lt;BiIter&gt;::value_type& rhs);
  template&lt;class BiIter&gt;
    bool operator&gt;(const sub_match&lt;BiIter&gt;& lhs,
                   const typename iterator_traits&lt;BiIter&gt;::value_type& rhs);
  template&lt;class BiIter&gt;
    bool operator&lt;=(const sub_match&lt;BiIter&gt;& lhs,
                    const typename iterator_traits&lt;BiIter&gt;::value_type& rhs);
  template&lt;class BiIter&gt;
    bool operator&gt;=(const sub_match&lt;BiIter&gt;& lhs,
                    const typename iterator_traits&lt;BiIter&gt;::value_type& rhs);</del>

  template&lt;class charT, class ST, class BiIter&gt;
    basic_ostream&lt;charT, ST&gt;&
      operator&lt;&lt;(basic_ostream&lt;charT, ST&gt;& os, const sub_match&lt;BiIter&gt;& m);

  // [re.results], class template match_results
  template&lt;class BidirectionalIterator,
           class Allocator = allocator&lt;sub_match&lt;BidirectionalIterator&gt;&gt;&gt;
    class match_results;

  using cmatch  = match_results&lt;const char*&gt;;
  using wcmatch = match_results&lt;const wchar_t*&gt;;
  using smatch  = match_results&lt;string::const_iterator&gt;;
  using wsmatch = match_results&lt;wstring::const_iterator&gt;;

<del>  // match_results comparisons
  template&lt;class BidirectionalIterator, class Allocator&gt;
    bool operator==(const match_results&lt;BidirectionalIterator, Allocator&gt;& m1,
                    const match_results&lt;BidirectionalIterator, Allocator&gt;& m2);
  template&lt;class BidirectionalIterator, class Allocator&gt;
    bool operator!=(const match_results&lt;BidirectionalIterator, Allocator&gt;& m1,
                    const match_results&lt;BidirectionalIterator, Allocator&gt;& m2);</del>

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

<p>Change 30.9 [re.submatch]:</p>
<blockquote><pre><code>namespace std {
  template&lt;class BidirectionalIterator&gt;
    class sub_match : public pair&lt;BidirectionalIterator, BidirectionalIterator&gt; {
    public:
      using value_type      =
              typename iterator_traits&lt;BidirectionalIterator&gt;::value_type;
      using difference_type =
              typename iterator_traits&lt;BidirectionalIterator&gt;::difference_type;
      using iterator        = BidirectionalIterator;
      using string_type     = basic_string&lt;value_type&gt;;

      bool matched;

      constexpr sub_match();

      difference_type length() const;
      operator string_type() const;
      string_type str() const;

      int compare(const sub_match& s) const;
      int compare(const string_type& s) const;
      int compare(const value_type* s) const;

      <ins>friend bool operator==(const sub_match& lhs, const sub_match& rhs);</ins>
      <ins>friend compare_three_way_result_t&lt;string_type&gt; operator&lt;=&gt;(const sub_match& lhs, const sub_match& rhs);</ins>

      <ins>template&lt;class ST, class SA&gt;</ins>
      <ins>  friend bool operator==(const sub_match& lhs, const basic_string&lt;value_type, ST, SA&gt;& rhs);</ins>
      <ins>template&lt;class ST, class SA&gt;</ins>
      <ins>  friend compare_three_way_result_t&lt;string_type&gt;</ins>
      <ins>    operator&lt;=&gt;(const sub_match& lhs, const basic_string&lt;value_type, ST, SA&gt;& rhs);</ins>

      <ins>friend bool operator==(const sub_match& lhs, const value_type* rhs);</ins>
      <ins>friend compare_three_way_result_t&lt;string_type&gt; operator&lt;=&gt;(const sub_match& lhs, const value_type* rhs);</ins>

      <ins>friend bool operator==(const sub_match& lhs, const value_type& rhs);</ins>
      <ins>friend compare_three_way_result_t&lt;string_type&gt; operator&lt;=&gt;(const sub_match& lhs, const value_type& rhs);</ins>      
    };
}</code></pre></blockquote>

<p>Replace the entirety of 30.9.2 [re.submatch.op] (all 42 non-member comparison operators, plus an <code class="language-cpp">operator&lt;&lt;</code>) with:</p>
<blockquote>
<p><pre><code><ins>friend bool operator==(const sub_match&amp; lhs, const sub_match&amp; rhs);</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">lhs.compare(rhs) == 0</code>.</ins>
<pre><code><ins>friend compare_three_way_result_t&lt;string_type&gt; operator&lt;=&gt;(const sub_match&amp; lhs, const sub_match&amp; rhs);</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">lhs.compare(rhs) &lt;=&gt; 0</code>.</ins>
<pre><code><ins>template&lt;class ST, class SA&gt;
  friend bool operator==(const sub_match&amp; lhs, const basic_string&lt;value_type, ST, SA&gt;&amp; rhs);</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">lhs.compare(string_type(rhs.data(), rhs.size())) == 0</code></ins>
<pre><code><ins>template&lt;class ST, class SA&gt;
  friend compare_three_way_result_t&lt;string_type&gt;
    operator&lt;=&gt;(const sub_match&amp; lhs, const basic_string&lt;value_type, ST, SA&gt;&amp; rhs);</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">lhs.compare(string_type(rhs.data(), rhs.size())) &lt;=&gt; 0</code></ins>
<pre><code><ins>friend bool operator==(const sub_match&amp; lhs, const value_type&ast; rhs);</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">lhs.compare(rhs) == 0</code>.</ins>
<pre><code><ins>friend compare_three_way_result_t&lt;string_type&gt; operator&lt;=&gt;(const sub_match&amp; lhs, const value_type&ast; rhs);</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">lhs.compare(rhs) &lt;=&gt; 0</code>.</ins>
<pre><code><ins>friend bool operator==(const sub_match&amp; lhs, const value_type&amp; rhs);</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">lhs.compare(string_type(1, rhs)) == 0</code>.</ins>
<pre><code><ins>friend compare_three_way_result_t&lt;string_type&gt; operator&lt;=&gt;(const sub_match&amp; lhs, const value_type&amp; rhs);</ins></code></pre>
<ins><em>Returns</em>: <code class="language-cpp">lhs.compare(string_type(1, rhs)) &lt;=&gt; 0</code>.</ins>
<pre><code>template&lt;class charT, class ST, class BiIter&gt;
  basic_ostream&lt;charT, ST&gt;&amp;
    operator&lt;&lt;(basic_ostream&lt;charT, ST&gt;&amp; os, const sub_match&lt;BiIter&gt;&amp; m);</code></pre>
<em>Returns</em>: <code class="language-cpp">os &lt;&lt; m.str()</code>.</p>
</blockquote>
<p>Change 30.10 [re.results]:</p>
<blockquote><pre><code>namespace std {
  template<class BidirectionalIterator,
           class Allocator = allocator<sub_match<BidirectionalIterator>>>
    class match_results {
    public:

      [...]
      // [re.results.swap], swap
      void swap(match_results& that);

      <ins>friend bool operator==(const match_results& m1, const match_results& m2);</ins>
    };
}</code></pre></blockquote>

<p>Change 30.10.8 [re.results.nonmember]:</p>
<blockquote>
<p><pre><code><del>template&lt;class BidirectionalIterator, class Allocator&gt;</del>
<ins>friend </ins>bool operator==(const match_results<del>&lt;BidirectionalIterator, Allocator&gt;</del>&amp; m1,
                const match_results<del>&lt;BidirectionalIterator, Allocator&gt;</del>&amp; m2);</code></pre>
<em>Returns</em>: <code class="language-cpp">true</code> if neither match result is ready [...]
<pre><code><del>template&lt;class BidirectionalIterator, class Allocator&gt;
bool operator!=(const match_results&lt;BidirectionalIterator, Allocator&gt;&amp; m1,
                const match_results&lt;BidirectionalIterator, Allocator&gt;&amp; m2);</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(m1 == m2)</code>.</del></p>
</blockquote>
<h3 id="clause-31-atomic-operations-library">4.16. Clause 31: Atomic operations library<a class="self-link" href="#clause-31-atomic-operations-library"></a></h3>
<p>No changes necessary.</p>
<h3 id="clause-32-thread-support-library">4.17. Clause 32: Thread support library<a class="self-link" href="#clause-32-thread-support-library"></a></h3>
<p>Change 32.3.2.1 [thread.thread.id]:</p>
<blockquote><pre><code>namespace std {
  class thread::id {
  public:
    id() noexcept;

    <ins>friend bool operator==(thread::id x, thread::id y) noexcept;</ins>
    <ins>friend strong_ordering operator<=>(thread::id x, thread::id y) noexcept;</ins>
  };

  <del>bool operator==(thread::id x, thread::id y) noexcept;</del>
  <del>bool operator!=(thread::id x, thread::id y) noexcept;</del>
  <del>bool operator&lt;(thread::id x, thread::id y) noexcept;</del>
  <del>bool operator&gt;(thread::id x, thread::id y) noexcept;</del>
  <del>bool operator&lt;=(thread::id x, thread::id y) noexcept;</del>
  <del>bool operator&gt;=(thread::id x, thread::id y) noexcept;</del>

  template&lt;class charT, class traits&gt;
    basic_ostream&lt;charT, traits&gt;&
      operator&lt;&lt;(basic_ostream&lt;charT, traits&gt;& out, thread::id id);

  // hash support
  template&lt;class T&gt; struct hash;
  template&lt;&gt; struct hash&lt;thread::id&gt;;
}</code></pre></blockquote>

<p>and paragraphs 6-11:</p>
<blockquote>
<p><pre><code><ins>friend </ins>bool operator==(thread::id x, thread::id y) noexcept;</code></pre>
<em>Returns</em>: <code class="language-cpp">true</code> only if <code class="language-cpp">x</code> and <code class="language-cpp">y</code> represent the same thread of execution or neither <code class="language-cpp">x</code> nor <code class="language-cpp">y</code> represents a thread of execution.
<pre><code><del>bool operator!=(thread::id x, thread::id y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(x == y)</code></del>
<pre><code><del>bool operator&lt;(thread::id x, thread::id y) noexcept;</del></code></pre>
<del><em>Returns</em>: A value such that <code class="language-cpp">operator&lt;</code> is a total ordering as described in [alg.sorting].</del>
<pre><code><ins>friend strong_ordering operator&lt;=&gt;(thread::id x, thread::id y) noexcept;</ins></code></pre>
<ins><em>Returns</em>: A value such that <code class="language-cpp">operator&lt;=&gt;</code> is a total ordering.</ins>
<pre><code><del>bool operator&gt;(thread::id x, thread::id y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">y &lt; x</code>.</del>
<pre><code><del>bool operator&lt;=(thread::id x, thread::id y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(y &lt; x)</code>.</del>
<pre><code><del>bool operator&gt;=(thread::id x, thread::id y) noexcept;</del></code></pre>
<del><em>Returns</em>: <code class="language-cpp">!(x &lt; y)</code>.</del></p>
</blockquote>
<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/papers/2019/p0790r2.html">[P0790R2]</a><span style="margin-left: 5px;">"Effect of operator&lt;=&gt; on the C++ Standard Library" by David Stone, 2019-01-21</span></li><li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0891r2.html">[P0891R2]</a><span style="margin-left: 5px;">"Make strong_order a Customization Point!" by Gašper Ažman, Jeff Snyder, 2019-01-20</span></li><li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1154r1.html">[P1154R1]</a><span style="margin-left: 5px;">"Type traits for structural comparison" by Arthur O'Dwyer, Jeff Snyder, 2019-01-19</span></li><li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1185r1.html">[P1185R1]</a><span style="margin-left: 5px;">"&lt;=&gt; != ==" by Barry Revzin, 2019-01-22</span></li><li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1186r1.html">[P1186R1]</a><span style="margin-left: 5px;">"When do you actually use &lt;=&gt;?" by Barry Revzin, 2019-01-22</span></li><li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1188r0.html">[P1188R0]</a><span style="margin-left: 5px;">"Library utilities for &lt;=&gt;" by Barry Revzin, 2019-01-22</span></li><li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1189r0.html">[P1189R0]</a><span style="margin-left: 5px;">"Add &lt;=&gt; to Library" by Barry Revzin, 2019-01-22</span></li><li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1191r0.html">[P1191R0]</a><span style="margin-left: 5px;">"Adding operator&lt;=&gt; to types that are not currently comparable" by David Stone, 2018-08-22</span></li><li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1295r0.html">[P1295R0]</a><span style="margin-left: 5px;">"Spaceship library update" by Tomasz Kamiński, 2018-10-07</span></li><li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1380r1.html">[P1380R1]</a><span style="margin-left: 5px;">"Ambiguity and Insecurities with Three-Way Comparison" by Lawrence Crowl, 2019-01-20</span></li></ul>
</html>