<!doctype html><html lang="en">
 <head>
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
  <title>p0332R2: Relaxed Incomplete Multidimensional Array Type Declaration</title>
<style data-fill-with="stylesheet">/******************************************************************************
 *                   Style sheet for the W3C specifications                   *
 *
 * Special classes handled by this style sheet include:
 *
 * Indices
 *   - .toc for the Table of Contents (<ol class="toc">)
 *     + <span class="secno"> for the section numbers
 *   - #toc for the Table of Contents (<nav id="toc">)
 *   - ul.index for Indices (<a href="#ref">term</a><span>, in §N.M</span>)
 *   - table.index for Index Tables (e.g. for properties or elements)
 *
 * Structural Markup
 *   - table.data for general data tables
 *     -> use 'scope' attribute, <colgroup>, <thead>, and <tbody> for best results !
 *     -> use <table class='complex data'> for extra-complex tables
 *     -> use <td class='long'> for paragraph-length cell content
 *     -> use <td class='pre'> when manual line breaks/indentation would help readability
 *   - dl.switch for switch statements
 *   - ol.algorithm for algorithms (helps to visualize nesting)
 *   - .figure and .caption (HTML4) and figure and figcaption (HTML5)
 *     -> .sidefigure for right-floated figures
 *   - ins/del
 *
 * Code
 *   - pre and code
 *
 * Special Sections
 *   - .note       for informative notes             (div, p, span, aside, details)
 *   - .example    for informative examples          (div, p, pre, span)
 *   - .issue      for issues                        (div, p, span)
 *   - .assertion  for assertions                    (div, p, span)
 *   - .advisement for loud normative statements     (div, p, strong)
 *   - .annoying-warning for spec obsoletion notices (div, aside, details)
 *
 * Definition Boxes
 *   - pre.def   for WebIDL definitions
 *   - table.def for tables that define other entities (e.g. CSS properties)
 *   - dl.def    for definition lists that define other entitles (e.g. HTML elements)
 *
 * Numbering
 *   - .secno for section numbers in .toc and headings (<span class='secno'>3.2</span>)
 *   - .marker for source-inserted example/figure/issue numbers (<span class='marker'>Issue 4</span>)
 *   - ::before styled for CSS-generated issue/example/figure numbers:
 *     -> Documents wishing to use this only need to add
 *        figcaption::before,
 *        .caption::before { content: "Figure "  counter(figure) " ";  }
 *        .example::before { content: "Example " counter(example) " "; }
 *        .issue::before   { content: "Issue "   counter(issue) " ";   }
 *
 * Header Stuff (ignore, just don't conflict with these classes)
 *   - .head for the header
 *   - .copyright for the copyright
 *
 * Miscellaneous
 *   - .overlarge for things that should be as wide as possible, even if
 *     that overflows the body text area. This can be used on an item or
 *     on its container, depending on the effect desired.
 *     Note that this styling basically doesn't help at all when printing,
 *     since A4 paper isn't much wider than the max-width here.
 *     It's better to design things to fit into a narrower measure if possible.
 *   - js-added ToC jump links (see fixup.js)
 *
 ******************************************************************************/

/******************************************************************************/
/*                                   Body                                     */
/******************************************************************************/

	body {
		counter-reset: example figure issue;

		/* Layout */
		max-width: 50em;               /* limit line length to 50em for readability   */
		margin: 0 auto;                /* center text within page                     */
		padding: 1.6em 1.5em 2em 50px; /* assume 16px font size for downlevel clients */
		padding: 1.6em 1.5em 2em calc(26px + 1.5em); /* leave space for status flag     */

		/* Typography */
		line-height: 1.5;
		font-family: sans-serif;
		widows: 2;
		orphans: 2;
		word-wrap: break-word;
		overflow-wrap: break-word;
		hyphens: auto;

		/* Colors */
		color: black;
		background: white top left fixed no-repeat;
		background-size: 25px auto;
	}


/******************************************************************************/
/*                         Front Matter & Navigation                          */
/******************************************************************************/

/** Header ********************************************************************/

	div.head { margin-bottom: 1em }
	div.head hr { border-style: solid; }

	div.head h1 {
		font-weight: bold;
		margin: 0 0 .1em;
		font-size: 220%;
	}

	div.head h2 { margin-bottom: 1.5em;}

/** W3C Logo ******************************************************************/

	.head .logo {
		float: right;
		margin: 0.4rem 0 0.2rem .4rem;
	}

	.head img[src*="logos/W3C"] {
		display: block;
		border: solid #1a5e9a;
		border-width: .65rem .7rem .6rem;
		border-radius: .4rem;
		background: #1a5e9a;
		color: white;
		font-weight: bold;
	}

	.head a:hover > img[src*="logos/W3C"],
	.head a:focus > img[src*="logos/W3C"] {
		opacity: .8;
	}

	.head a:active > img[src*="logos/W3C"] {
		background: #c00;
		border-color: #c00;
	}

	/* see also additional rules in Link Styling section */

/** Copyright *****************************************************************/

	p.copyright,
	p.copyright small { font-size: small }

/** Back to Top / ToC Toggle **************************************************/

	@media print {
		#toc-nav {
			display: none;
		}
	}
	@media not print {
		#toc-nav {
			position: fixed;
			z-index: 2;
			bottom: 0; left: 0;
			margin: 0;
			min-width: 1.33em;
			border-top-right-radius: 2rem;
			box-shadow: 0 0 2px;
			font-size: 1.5em;
			color: black;
		}
		#toc-nav > a {
			display: block;
			white-space: nowrap;

			height: 1.33em;
			padding: .1em 0.3em;
			margin: 0;

			background: white;
			box-shadow: 0 0 2px;
			border: none;
			border-top-right-radius: 1.33em;
			background: white;
		}
		#toc-nav > #toc-jump {
			padding-bottom: 2em;
			margin-bottom: -1.9em;
		}

		#toc-nav > a:hover,
		#toc-nav > a:focus {
			background: #f8f8f8;
		}
		#toc-nav > a:not(:hover):not(:focus) {
			color: #707070;
		}

		/* statusbar gets in the way on keyboard focus; remove once browsers fix */
		#toc-nav > a[href="#toc"]:not(:hover):focus:last-child {
			padding-bottom: 1.5rem;
		}

		#toc-nav:not(:hover) > a:not(:focus) > span + span {
			/* Ideally this uses :focus-within on #toc-nav */
			display: none;
		}
		#toc-nav > a > span + span {
			padding-right: 0.2em;
		}

		#toc-toggle-inline {
			vertical-align: 0.05em;
			font-size: 80%;
			color: gray;
			color: hsla(203,20%,40%,.7);
			border-style: none;
			background: transparent;
			position: relative;
		}
		#toc-toggle-inline:hover:not(:active),
		#toc-toggle-inline:focus:not(:active) {
			text-shadow: 1px 1px silver;
			top: -1px;
			left: -1px;
		}

		#toc-nav :active {
			color: #C00;
		}
	}

/** ToC Sidebar ***************************************************************/

	/* Floating sidebar */
	@media screen {
		body.toc-sidebar #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			max-width: 80%;
			max-width: calc(100% - 2em - 26px);
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			background: inherit;
			background-color: #f7f8f9;
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
		}
		body.toc-sidebar #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
		}
		body.toc-sidebar #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	/* Hide main scroller when only the ToC is visible anyway */
	@media screen and (max-width: 28em) {
		body.toc-sidebar {
			overflow: hidden;
		}
	}

	/* Sidebar with its own space */
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			background: inherit;
			background-color: #f7f8f9;
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
		}
		body:not(.toc-inline) #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
		}

		body:not(.toc-inline) {
			padding-left: 29em;
		}
		/* See also Overflow section at the bottom */

		body:not(.toc-inline) #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) {
			margin: 0 4em;
		}
	}

/******************************************************************************/
/*                                Sectioning                                  */
/******************************************************************************/

/** Headings ******************************************************************/

	h1, h2, h3, h4, h5, h6, dt {
		page-break-after: avoid;
		page-break-inside: avoid;
		font: 100% sans-serif;   /* Reset all font styling to clear out UA styles */
		font-family: inherit;    /* Inherit the font family. */
		line-height: 1.2;        /* Keep wrapped headings compact */
		hyphens: manual;         /* Hyphenated headings look weird */
	}

	h2, h3, h4, h5, h6 {
		margin-top: 3rem;
	}

	h1, h2, h3 {
		color: #005A9C;
		background: transparent;
	}

	h1 { font-size: 170%; }
	h2 { font-size: 140%; }
	h3 { font-size: 120%; }
	h4 { font-weight: bold; }
	h5 { font-style: italic; }
	h6 { font-variant: small-caps; }
	dt { font-weight: bold; }

/** Subheadings ***************************************************************/

	h1 + h2,
	#subtitle {
		/* #subtitle is a subtitle in an H2 under the H1 */
		margin-top: 0;
	}
	h2 + h3,
	h3 + h4,
	h4 + h5,
	h5 + h6 {
		margin-top: 1.2em; /* = 1 x line-height */
	}

/** Section divider ***********************************************************/

	:not(.head) > hr {
		font-size: 1.5em;
		text-align: center;
		margin: 1em auto;
		height: auto;
		border: transparent solid 0;
		background: transparent;
	}
	:not(.head) > hr::before {
		content: "\2727\2003\2003\2727\2003\2003\2727";
	}

/******************************************************************************/
/*                            Paragraphs and Lists                            */
/******************************************************************************/

	p {
		margin: 1em 0;
	}

	dd > p:first-child,
	li > p:first-child {
		margin-top: 0;
	}

	ul, ol {
		margin-left: 0;
		padding-left: 2em;
	}

	li {
		margin: 0.25em 0 0.5em;
		padding: 0;
	}

	dl dd {
		margin: 0 0 .5em 2em;
	}

	.head dd + dd { /* compact for header */
		margin-top: -.5em;
	}

	/* Style for algorithms */
	ol.algorithm ol:not(.algorithm),
	.algorithm > ol ol:not(.algorithm) {
	 border-left: 0.5em solid #DEF;
	}

	/* Put nice boxes around each algorithm. */
	[data-algorithm]:not(.heading) {
	  padding: .5em;
	  border: thin solid #ddd; border-radius: .5em;
	  margin: .5em calc(-0.5em - 1px);
	}
	[data-algorithm]:not(.heading) > :first-child {
	  margin-top: 0;
	}
	[data-algorithm]:not(.heading) > :last-child {
	  margin-bottom: 0;
	}

	/* Style for switch/case <dl>s */
	dl.switch > dd > ol.only,
	dl.switch > dd > .only > ol {
	 margin-left: 0;
	}
	dl.switch > dd > ol.algorithm,
	dl.switch > dd > .algorithm > ol {
	 margin-left: -2em;
	}
	dl.switch {
	 padding-left: 2em;
	}
	dl.switch > dt {
	 text-indent: -1.5em;
	 margin-top: 1em;
	}
	dl.switch > dt + dt {
	 margin-top: 0;
	}
	dl.switch > dt::before {
	 content: '\21AA';
	 padding: 0 0.5em 0 0;
	 display: inline-block;
	 width: 1em;
	 text-align: right;
	 line-height: 0.5em;
	}

/** Terminology Markup ********************************************************/


/******************************************************************************/
/*                                 Inline Markup                              */
/******************************************************************************/

/** Terminology Markup ********************************************************/
	dfn   { /* Defining instance */
		font-weight: bolder;
	}
	a > i { /* Instance of term */
		font-style: normal;
	}
	dt dfn code, code.idl {
		font-size: medium;
	}
	dfn var {
		font-style: normal;
	}

/** Change Marking ************************************************************/

	del { color: red;  text-decoration: line-through; }
	ins { color: #080; text-decoration: underline;    }

/** Miscellaneous improvements to inline formatting ***************************/

	sup {
		vertical-align: super;
		font-size: 80%
	}

/******************************************************************************/
/*                                    Code                                    */
/******************************************************************************/

/** General monospace/pre rules ***********************************************/

	pre, code, samp {
		font-family: Menlo, Consolas, "DejaVu Sans Mono", Monaco, monospace;
		font-size: .9em;
		page-break-inside: avoid;
		hyphens: none;
		text-transform: none;
	}
	pre code,
	code code {
		font-size: 100%;
	}

	pre {
		margin-top: 1em;
		margin-bottom: 1em;
		overflow: auto;
	}

/** Inline Code fragments *****************************************************/

  /* Do something nice. */

/******************************************************************************/
/*                                    Links                                   */
/******************************************************************************/

/** General Hyperlinks ********************************************************/

	/* We hyperlink a lot, so make it less intrusive */
	a[href] {
		color: #034575;
		text-decoration: none;
		border-bottom: 1px solid #707070;
		/* Need a bit of extending for it to look okay */
		padding: 0 1px 0;
		margin: 0 -1px 0;
	}
	a:visited {
		border-bottom-color: #BBB;
	}

	/* Use distinguishing colors when user is interacting with the link */
	a[href]:focus,
	a[href]:hover {
		background: #f8f8f8;
		background: rgba(75%, 75%, 75%, .25);
		border-bottom-width: 3px;
		margin-bottom: -2px;
	}
	a[href]:active {
		color: #C00;
		border-color: #C00;
	}

	/* Backout above styling for W3C logo */
	.head .logo,
	.head .logo a {
		border: none;
		text-decoration: none;
		background: transparent;
	}

/******************************************************************************/
/*                                    Images                                  */
/******************************************************************************/

	img {
		border-style: none;
	}

	/* For autogen numbers, add
	   .caption::before, figcaption::before { content: "Figure " counter(figure) ". "; }
	*/

	figure, .figure, .sidefigure {
		page-break-inside: avoid;
		text-align: center;
		margin: 2.5em 0;
	}
	.figure img,    .sidefigure img,    figure img,
	.figure object, .sidefigure object, figure object {
		max-width: 100%;
		margin: auto;
	}
	.figure pre, .sidefigure pre, figure pre {
		text-align: left;
		display: table;
		margin: 1em auto;
	}
	.figure table, figure table {
		margin: auto;
	}
	@media screen and (min-width: 20em) {
		.sidefigure {
			float: right;
			width: 50%;
			margin: 0 0 0.5em 0.5em
		}
	}
	.caption, figcaption, caption {
		font-style: italic;
		font-size: 90%;
	}
	.caption::before, figcaption::before, figcaption > .marker {
		font-weight: bold;
	}
	.caption, figcaption {
		counter-increment: figure;
	}

	/* DL list is indented 2em, but figure inside it is not */
	dd > .figure, dd > figure { margin-left: -2em }

/******************************************************************************/
/*                             Colored Boxes                                  */
/******************************************************************************/

	.issue, .note, .example, .assertion, .advisement, blockquote {
		padding: .5em;
		border: .5em;
		border-left-style: solid;
		page-break-inside: avoid;
	}
	span.issue, span.note {
		padding: .1em .5em .15em;
		border-right-style: solid;
	}

	.issue,
	.note,
	.example,
	.advisement,
	.assertion,
	blockquote {
		margin: 1em auto;
	}
	.note  > p:first-child,
	.issue > p:first-child,
	blockquote > :first-child {
		margin-top: 0;
	}
	blockquote > :last-child {
		margin-bottom: 0;
	}

/** Blockquotes ***************************************************************/

	blockquote {
		border-color: silver;
	}

/** Open issue ****************************************************************/

	.issue {
		border-color: #E05252;
		background: #FBE9E9;
		counter-increment: issue;
		overflow: auto;
	}
	.issue::before, .issue > .marker {
		text-transform: uppercase;
		color: #AE1E1E;
		padding-right: 1em;
		text-transform: uppercase;
	}
	/* Add .issue::before { content: "Issue " counter(issue) " "; } for autogen numbers,
	   or use class="marker" to mark up the issue number in source. */

/** Example *******************************************************************/

	.example {
		border-color: #E0CB52;
		background: #FCFAEE;
		counter-increment: example;
		overflow: auto;
		clear: both;
	}
	.example::before, .example > .marker {
		text-transform: uppercase;
		color: #827017;
		min-width: 7.5em;
		display: block;
	}
	/* Add .example::before { content: "Example " counter(example) " "; } for autogen numbers,
	   or use class="marker" to mark up the example number in source. */

/** Non-normative Note ********************************************************/

	.note {
		border-color: #52E052;
		background: #E9FBE9;
		overflow: auto;
	}

	.note::before, .note > .marker,
	details.note > summary::before,
	details.note > summary > .marker {
		text-transform: uppercase;
		display: block;
		color: hsl(120, 70%, 30%);
	}
	/* Add .note::before { content: "Note"; } for autogen label,
	   or use class="marker" to mark up the label in source. */

	details.note > summary {
		display: block;
		color: hsl(120, 70%, 30%);
	}
	details.note[open] > summary {
		border-bottom: 1px silver solid;
	}

/** Assertion Box *************************************************************/
	/*  for assertions in algorithms */

	.assertion {
		border-color: #AAA;
		background: #EEE;
	}

/** Advisement Box ************************************************************/
	/*  for attention-grabbing normative statements */

	.advisement {
		border-color: orange;
		border-style: none solid;
		background: #FFEECC;
	}
	strong.advisement {
		display: block;
		text-align: center;
	}
	.advisement > .marker {
		color: #B35F00;
	}

/** Spec Obsoletion Notice ****************************************************/
	/* obnoxious obsoletion notice for older/abandoned specs. */

	details {
		display: block;
	}
	summary {
		font-weight: bolder;
	}

	.annoying-warning:not(details),
	details.annoying-warning:not([open]) > summary,
	details.annoying-warning[open] {
		background: #fdd;
		color: red;
		font-weight: bold;
		padding: .75em 1em;
		border: thick red;
		border-style: solid;
		border-radius: 1em;
	}
	.annoying-warning :last-child {
		margin-bottom: 0;
	}

@media not print {
	details.annoying-warning[open] {
		position: fixed;
		left: 1em;
		right: 1em;
		bottom: 1em;
		z-index: 1000;
	}
}

	details.annoying-warning:not([open]) > summary {
		text-align: center;
	}

/** Entity Definition Boxes ***************************************************/

	.def {
		padding: .5em 1em;
		background: #DEF;
		margin: 1.2em 0;
		border-left: 0.5em solid #8CCBF2;
	}

/******************************************************************************/
/*                                    Tables                                  */
/******************************************************************************/

	th, td {
		text-align: left;
		text-align: start;
	}

/** Property/Descriptor Definition Tables *************************************/

	table.def {
		/* inherits .def box styling, see above */
		width: 100%;
		border-spacing: 0;
	}

	table.def td,
	table.def th {
		padding: 0.5em;
		vertical-align: baseline;
		border-bottom: 1px solid #bbd7e9;
	}

	table.def > tbody > tr:last-child th,
	table.def > tbody > tr:last-child td {
		border-bottom: 0;
	}

	table.def th {
		font-style: italic;
		font-weight: normal;
		padding-left: 1em;
		width: 3em;
	}

	/* For when values are extra-complex and need formatting for readability */
	table td.pre {
		white-space: pre-wrap;
	}

	/* A footnote at the bottom of a def table */
	table.def           td.footnote {
		padding-top: 0.6em;
	}
	table.def           td.footnote::before {
		content: " ";
		display: block;
		height: 0.6em;
		width: 4em;
		border-top: thin solid;
	}

/** Data tables (and properly marked-up index tables) *************************/
	/*
		 <table class="data"> highlights structural relationships in a table
		 when correct markup is used (e.g. thead/tbody, th vs. td, scope attribute)

		 Use class="complex data" for particularly complicated tables --
		 (This will draw more lines: busier, but clearer.)

		 Use class="long" on table cells with paragraph-like contents
		 (This will adjust text alignment accordingly.)
		 Alternately use class="longlastcol" on tables, to have the last column assume "long".
	*/

	table {
		word-wrap: normal;
		overflow-wrap: normal;
		hyphens: manual;
	}

	table.data,
	table.index {
		margin: 1em auto;
		border-collapse: collapse;
		border: hidden;
		width: 100%;
	}
	table.data caption,
	table.index caption {
		max-width: 50em;
		margin: 0 auto 1em;
	}

	table.data td,  table.data th,
	table.index td, table.index th {
		padding: 0.5em 1em;
		border-width: 1px;
		border-color: silver;
		border-top-style: solid;
	}

	table.data thead td:empty {
		padding: 0;
		border: 0;
	}

	table.data  thead,
	table.index thead,
	table.data  tbody,
	table.index tbody {
		border-bottom: 2px solid;
	}

	table.data colgroup,
	table.index colgroup {
		border-left: 2px solid;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		border-right: 2px solid;
		border-top: 1px solid silver;
		padding-right: 1em;
	}

	table.data th[colspan],
	table.data td[colspan] {
		text-align: center;
	}

	table.complex.data th,
	table.complex.data td {
		border: 1px solid silver;
		text-align: center;
	}

	table.data.longlastcol td:last-child,
	table.data td.long {
	 vertical-align: baseline;
	 text-align: left;
	}

	table.data img {
		vertical-align: middle;
	}


/*
Alternate table alignment rules

	table.data,
	table.index {
		text-align: center;
	}

	table.data  thead th[scope="row"],
	table.index thead th[scope="row"] {
		text-align: right;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		text-align: right;
	}

Possible extra rowspan handling

	table.data  tbody th[rowspan]:not([rowspan='1']),
	table.index tbody th[rowspan]:not([rowspan='1']),
	table.data  tbody td[rowspan]:not([rowspan='1']),
	table.index tbody td[rowspan]:not([rowspan='1']) {
		border-left: 1px solid silver;
	}

	table.data  tbody th[rowspan]:first-child,
	table.index tbody th[rowspan]:first-child,
	table.data  tbody td[rowspan]:first-child,
	table.index tbody td[rowspan]:first-child{
		border-left: 0;
		border-right: 1px solid silver;
	}
*/

/******************************************************************************/
/*                                  Indices                                   */
/******************************************************************************/


/** Table of Contents *********************************************************/

	.toc a {
		/* More spacing; use padding to make it part of the click target. */
		padding-top: 0.1rem;
		/* Larger, more consistently-sized click target */
		display: block;
		/* Reverse color scheme */
		color: black;
		border-color: #3980B5;
		border-bottom-width: 3px !important;
		margin-bottom: 0px !important;
	}
	.toc a:visited {
		border-color: #054572;
	}
	.toc a:not(:focus):not(:hover) {
		/* Allow colors to cascade through from link styling */
		border-bottom-color: transparent;
	}

	.toc, .toc ol, .toc ul, .toc li {
		list-style: none; /* Numbers must be inlined into source */
		/* because generated content isn't search/selectable and markers can't do multilevel yet */
		margin:  0;
		padding: 0;
		line-height: 1.1rem; /* consistent spacing */
	}

	/* ToC not indented until third level, but font style & margins show hierarchy */
	.toc > li             { font-weight: bold;   }
	.toc > li li          { font-weight: normal; }
	.toc > li li li       { font-size:   95%;    }
	.toc > li li li li    { font-size:   90%;    }
	.toc > li li li li li { font-size:   85%;    }

	.toc > li             { margin: 1.5rem 0;    }
	.toc > li li          { margin: 0.3rem 0;    }
	.toc > li li li       { margin-left: 2rem;   }

	/* Section numbers in a column of their own */
	.toc .secno {
		float: left;
		width: 4rem;
		white-space: nowrap;
	}
	.toc > li li li li .secno {
		font-size: 85%;
	}
	.toc > li li li li li .secno {
		font-size: 100%;
	}

	:not(li) > .toc              { margin-left:  5rem; }
	.toc .secno                  { margin-left: -5rem; }
	.toc > li li li .secno       { margin-left: -7rem; }
	.toc > li li li li .secno    { margin-left: -9rem; }
	.toc > li li li li li .secno { margin-left: -11rem; }

	/* Tighten up indentation in narrow ToCs */
	@media (max-width: 30em) {
		:not(li) > .toc              { margin-left:  4rem; }
		.toc .secno                  { margin-left: -4rem; }
		.toc > li li li              { margin-left:  1rem; }
		.toc > li li li .secno       { margin-left: -5rem; }
		.toc > li li li li .secno    { margin-left: -6rem; }
		.toc > li li li li li .secno { margin-left: -7rem; }
	}
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) :not(li) > .toc              { margin-left:  4rem; }
		body:not(.toc-inline) .toc .secno                  { margin-left: -4rem; }
		body:not(.toc-inline) .toc > li li li              { margin-left:  1rem; }
		body:not(.toc-inline) .toc > li li li .secno       { margin-left: -5rem; }
		body:not(.toc-inline) .toc > li li li li .secno    { margin-left: -6rem; }
		body:not(.toc-inline) .toc > li li li li li .secno { margin-left: -7rem; }
	}
	body.toc-sidebar #toc :not(li) > .toc              { margin-left:  4rem; }
	body.toc-sidebar #toc .toc .secno                  { margin-left: -4rem; }
	body.toc-sidebar #toc .toc > li li li              { margin-left:  1rem; }
	body.toc-sidebar #toc .toc > li li li .secno       { margin-left: -5rem; }
	body.toc-sidebar #toc .toc > li li li li .secno    { margin-left: -6rem; }
	body.toc-sidebar #toc .toc > li li li li li .secno { margin-left: -7rem; }

	.toc li {
		clear: both;
	}


/** Index *********************************************************************/

	/* Index Lists: Layout */
	ul.index       { margin-left: 0; columns: 15em; text-indent: 1em hanging; }
	ul.index li    { margin-left: 0; list-style: none; break-inside: avoid; }
	ul.index li li { margin-left: 1em }
	ul.index dl    { margin-top: 0; }
	ul.index dt    { margin: .2em 0 .2em 20px;}
	ul.index dd    { margin: .2em 0 .2em 40px;}
	/* Index Lists: Typography */
	ul.index ul,
	ul.index dl { font-size: smaller; }
	@media not print {
		ul.index li span {
			white-space: nowrap;
			color: transparent; }
		ul.index li a:hover + span,
		ul.index li a:focus + span {
			color: #707070;
		}
	}

/** Index Tables *****************************************************/
	/* See also the data table styling section, which this effectively subclasses */

	table.index {
		font-size: small;
		border-collapse: collapse;
		border-spacing: 0;
		text-align: left;
		margin: 1em 0;
	}

	table.index td,
	table.index th {
		padding: 0.4em;
	}

	table.index tr:hover td:not([rowspan]),
	table.index tr:hover th:not([rowspan]) {
		background: #f7f8f9;
	}

	/* The link in the first column in the property table (formerly a TD) */
	table.index th:first-child a {
		font-weight: bold;
	}

/******************************************************************************/
/*                                    Print                                   */
/******************************************************************************/

	@media print {
		/* Pages have their own margins. */
		html {
			margin: 0;
		}
		/* Serif for print. */
		body {
			font-family: serif;
		}
	}
	@page {
		margin: 1.5cm 1.1cm;
	}

/******************************************************************************/
/*                                    Legacy                                  */
/******************************************************************************/

	/* This rule is inherited from past style sheets. No idea what it's for. */
	.hide { display: none }



/******************************************************************************/
/*                             Overflow Control                               */
/******************************************************************************/

	.figure .caption, .sidefigure .caption, figcaption {
		/* in case figure is overlarge, limit caption to 50em */
		max-width: 50rem;
		margin-left: auto;
		margin-right: auto;
	}
	.overlarge > table {
		/* limit preferred width of table */
		max-width: 50em;
		margin-left: auto;
		margin-right: auto;
	}

	@media (min-width: 55em) {
		.overlarge {
			margin-left: calc(13px + 26.5rem - 50vw);
			margin-right: calc(13px + 26.5rem - 50vw);
			max-width: none;
		}
	}
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) .overlarge {
			/* 30.5em body padding 50em content area */
			margin-left: calc(40em - 50vw) !important;
			margin-right: calc(40em - 50vw) !important;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) .overlarge {
			/* 4em html margin 30.5em body padding 50em content area */
			margin-left: 0 !important;
			margin-right: calc(84.5em - 100vw) !important;
		}
	}

	@media not print {
		.overlarge {
			overflow-x: auto;
			/* See Lea Verou's explanation background-attachment:
			 * http://lea.verou.me/2012/04/background-attachment-local/
			 *
			background: top left  / 4em 100% linear-gradient(to right,  #ffffff, rgba(255, 255, 255, 0)) local,
			            top right / 4em 100% linear-gradient(to left, #ffffff, rgba(255, 255, 255, 0)) local,
			            top left  / 1em 100% linear-gradient(to right,  #c3c3c5, rgba(195, 195, 197, 0)) scroll,
			            top right / 1em 100% linear-gradient(to left, #c3c3c5, rgba(195, 195, 197, 0)) scroll,
			            white;
			background-repeat: no-repeat;
			*/
		}
	}
</style>
<style type="text/css">
    table, th, td {
      border: 1px solid black;
      border-collapse: collapse;
      vertical-align: top;
    }
    th, td {
      border-left: none;
      border-right: none;
      padding: 0px 10px;
    }
    th {
      text-align: center;
    }
  </style>
  <meta content="Bikeshed version 405e5d97c9744a2182892308d7a95a41731f9220" name="generator">
  <link href="https://kokkos.github.io/array_ref/proposals/P0332.html" rel="canonical">
<style>/* style-md-lists */

/* This is a weird hack for me not yet following the commonmark spec
   regarding paragraph and lists. */
[data-md] > :first-child {
    margin-top: 0;
}
[data-md] > :last-child {
    margin-bottom: 0;
}</style>
<style>/* style-counters */

body {
    counter-reset: example figure issue;
}
.issue {
    counter-increment: issue;
}
.issue:not(.no-marker)::before {
    content: "Issue " counter(issue);
}

.example {
    counter-increment: example;
}
.example:not(.no-marker)::before {
    content: "Example " counter(example);
}
.invalid.example:not(.no-marker)::before,
.illegal.example:not(.no-marker)::before {
    content: "Invalid Example" counter(example);
}

figcaption {
    counter-increment: figure;
}
figcaption:not(.no-marker)::before {
    content: "Figure " counter(figure) " ";
}</style>
<style>/* style-syntax-highlighting */

.highlight:not(.idl) { background: hsl(24, 20%, 95%); }
code.highlight { padding: .1em; border-radius: .3em; }
pre.highlight, pre > code.highlight { display: block; padding: 1em; margin: .5em 0; overflow: auto; border-radius: 0; }
.highlight .c { color: #708090 } /* Comment */
.highlight .k { color: #990055 } /* Keyword */
.highlight .l { color: #000000 } /* Literal */
.highlight .n { color: #0077aa } /* Name */
.highlight .o { color: #999999 } /* Operator */
.highlight .p { color: #999999 } /* Punctuation */
.highlight .cm { color: #708090 } /* Comment.Multiline */
.highlight .cp { color: #708090 } /* Comment.Preproc */
.highlight .c1 { color: #708090 } /* Comment.Single */
.highlight .cs { color: #708090 } /* Comment.Special */
.highlight .kc { color: #990055 } /* Keyword.Constant */
.highlight .kd { color: #990055 } /* Keyword.Declaration */
.highlight .kn { color: #990055 } /* Keyword.Namespace */
.highlight .kp { color: #990055 } /* Keyword.Pseudo */
.highlight .kr { color: #990055 } /* Keyword.Reserved */
.highlight .kt { color: #990055 } /* Keyword.Type */
.highlight .ld { color: #000000 } /* Literal.Date */
.highlight .m { color: #000000 } /* Literal.Number */
.highlight .s { color: #a67f59 } /* Literal.String */
.highlight .na { color: #0077aa } /* Name.Attribute */
.highlight .nc { color: #0077aa } /* Name.Class */
.highlight .no { color: #0077aa } /* Name.Constant */
.highlight .nd { color: #0077aa } /* Name.Decorator */
.highlight .ni { color: #0077aa } /* Name.Entity */
.highlight .ne { color: #0077aa } /* Name.Exception */
.highlight .nf { color: #0077aa } /* Name.Function */
.highlight .nl { color: #0077aa } /* Name.Label */
.highlight .nn { color: #0077aa } /* Name.Namespace */
.highlight .py { color: #0077aa } /* Name.Property */
.highlight .nt { color: #669900 } /* Name.Tag */
.highlight .nv { color: #222222 } /* Name.Variable */
.highlight .ow { color: #999999 } /* Operator.Word */
.highlight .mb { color: #000000 } /* Literal.Number.Bin */
.highlight .mf { color: #000000 } /* Literal.Number.Float */
.highlight .mh { color: #000000 } /* Literal.Number.Hex */
.highlight .mi { color: #000000 } /* Literal.Number.Integer */
.highlight .mo { color: #000000 } /* Literal.Number.Oct */
.highlight .sb { color: #a67f59 } /* Literal.String.Backtick */
.highlight .sc { color: #a67f59 } /* Literal.String.Char */
.highlight .sd { color: #a67f59 } /* Literal.String.Doc */
.highlight .s2 { color: #a67f59 } /* Literal.String.Double */
.highlight .se { color: #a67f59 } /* Literal.String.Escape */
.highlight .sh { color: #a67f59 } /* Literal.String.Heredoc */
.highlight .si { color: #a67f59 } /* Literal.String.Interpol */
.highlight .sx { color: #a67f59 } /* Literal.String.Other */
.highlight .sr { color: #a67f59 } /* Literal.String.Regex */
.highlight .s1 { color: #a67f59 } /* Literal.String.Single */
.highlight .ss { color: #a67f59 } /* Literal.String.Symbol */
.highlight .vc { color: #0077aa } /* Name.Variable.Class */
.highlight .vg { color: #0077aa } /* Name.Variable.Global */
.highlight .vi { color: #0077aa } /* Name.Variable.Instance */
.highlight .il { color: #000000 } /* Literal.Number.Integer.Long */
</style>
<style>/* style-selflinks */

.heading, .issue, .note, .example, li, dt {
    position: relative;
}
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;
}
a.self-link:hover {
    opacity: 1;
}
.heading > a.self-link {
    font-size: 83%;
}
li > a.self-link {
    left: calc(-1 * (3.5rem - 26px) - 2em);
}
dfn > a.self-link {
    top: auto;
    left: auto;
    opacity: 0;
    width: 1.5em;
    height: 1.5em;
    background: gray;
    color: white;
    font-style: normal;
    transition: opacity .2s, background-color .2s, color .2s;
}
dfn:hover > a.self-link {
    opacity: 1;
}
dfn > a.self-link:hover {
    color: black;
}

a.self-link::before            { content: "¶"; }
.heading > a.self-link::before { content: "§"; }
dfn > a.self-link::before      { content: "#"; }</style>
<style>/* style-autolinks */

.css.css, .property.property, .descriptor.descriptor {
    color: #005a9c;
    font-size: inherit;
    font-family: inherit;
}
.css::before, .property::before, .descriptor::before {
    content: "‘";
}
.css::after, .property::after, .descriptor::after {
    content: "’";
}
.property, .descriptor {
    /* Don't wrap property and descriptor names */
    white-space: nowrap;
}
.type { /* CSS value <type> */
    font-style: italic;
}
pre .property::before, pre .property::after {
    content: "";
}
[data-link-type="property"]::before,
[data-link-type="propdesc"]::before,
[data-link-type="descriptor"]::before,
[data-link-type="value"]::before,
[data-link-type="function"]::before,
[data-link-type="at-rule"]::before,
[data-link-type="selector"]::before,
[data-link-type="maybe"]::before {
    content: "‘";
}
[data-link-type="property"]::after,
[data-link-type="propdesc"]::after,
[data-link-type="descriptor"]::after,
[data-link-type="value"]::after,
[data-link-type="function"]::after,
[data-link-type="at-rule"]::after,
[data-link-type="selector"]::after,
[data-link-type="maybe"]::after {
    content: "’";
}

[data-link-type].production::before,
[data-link-type].production::after,
.prod [data-link-type]::before,
.prod [data-link-type]::after {
    content: "";
}

[data-link-type=element],
[data-link-type=element-attr] {
    font-family: Menlo, Consolas, "DejaVu Sans Mono", monospace;
    font-size: .9em;
}
[data-link-type=element]::before { content: "<" }
[data-link-type=element]::after  { content: ">" }

[data-link-type=biblio] {
    white-space: pre;
}</style>
 <body class="h-entry">
  <div class="head">
   <p data-fill-with="logo"></p>
   <h1 class="p-name no-ref" id="title">p0332R2<br>Relaxed Incomplete Multidimensional Array Type Declaration</h1>
   <h2 class="no-num no-toc no-ref heading settled" id="subtitle"><span class="content">Published Proposal, <time class="dt-updated" datetime="2018-02-10">10 February 2018</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt>This version:
     <dd><a class="u-url" href="https://kokkos.github.io/array_ref/proposals/P0332.html">https://kokkos.github.io/array_ref/proposals/P0332.html</a>
     <dt>Authors:
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:hcedwar@sandia.gov">H. Carter Edwards</a>
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:dsunder@sandia.gov">Daniel Sunderland</a>
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:crtrott@sandia.gov">Christian Trott</a>
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:dshollm@sandia.gov">David Hollman</a>
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:mbianco@cscs.ch">Mauro Bianco</a>
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:athanasios.iliopoulos@nrl.navy.mil">Athanasios Iliopoulos</a>
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:john.michopoulos@nrl.navy.mil">John Michopoulos</a>
     <dt>Audience:
     <dd>EWG
     <dt>Project:
     <dd>ISO JTC1/SC22/WG21: Programming Language C++
    </dl>
   </div>
   <div data-fill-with="warning"></div>
   <hr title="Separator for header">
  </div>
  <div class="p-summary" data-fill-with="abstract">
   <h2 class="no-num no-toc no-ref heading settled" id="abstract"><span class="content">Abstract</span></h2>
   <p>Significantly improve usability of

the mdspan multidimensional array library
by providing users with a concise and intuitive syntax
for specifying static and dynamic dimensions.</p>
  </div>
  <nav data-fill-with="table-of-contents" id="toc">
   <h2 class="no-num no-toc no-ref" id="contents">Table of Contents</h2>
   <ol class="toc" role="directory">
    <li>
     <a href="#revision-history"><span class="secno">1</span> <span class="content">Revision History</span></a>
     <ol class="toc">
      <li><a href="#n4356--original-proposal-2015-lenexa"><span class="secno">1.1</span> <span class="content"><span>[N4356]</span> : Original proposal, 2015-Lenexa</span></a>
      <li><a href="#p0332r0"><span class="secno">1.2</span> <span class="content"><span>[P0332r0]</span></span></a>
      <li><a href="#p0332r1"><span class="secno">1.3</span> <span class="content"><span>[P0332r1]</span></span></a>
      <li><a href="#p0332r2"><span class="secno">1.4</span> <span class="content">P0332r2</span></a>
     </ol>
    <li>
     <a href="#motivation"><span class="secno">2</span> <span class="content">Motivation</span></a>
     <ol class="toc">
      <li><a href="#array-type-for-mdspan"><span class="secno">2.1</span> <span class="content">Array type for <code class="highlight"><span class="n">mdspan</span></code></span></a>
      <li><a href="#why-not"><span class="secno">2.2</span> <span class="content">Why Not</span></a>
      <li><a href="#explicit-and-implicit-extents"><span class="secno">2.3</span> <span class="content">Explicit and Implicit Extents</span></a>
      <li><a href="#usability-by-mathematicians-scientists-and-engineers"><span class="secno">2.4</span> <span class="content">Usability by Mathematicians, Scientists, and Engineers</span></a>
      <li><a href="#clarifying-difference-between-array-type-and-array-object-declarations"><span class="secno">2.5</span> <span class="content">Clarifying difference between array type and array object declarations</span></a>
     </ol>
    <li>
     <a href="#proposal"><span class="secno">3</span> <span class="content">Proposal</span></a>
     <ol class="toc">
      <li><a href="#clarification-of-incomplete-types"><span class="secno">3.1</span> <span class="content">Clarification of incomplete types</span></a>
      <li><a href="#clarification-and-relaxation-of-array-type"><span class="secno">3.2</span> <span class="content">Clarification and relaxation of array type</span></a>
      <li><a href="#type_traits-interaction"><span class="secno">3.3</span> <span class="content">type_traits interaction</span></a>
     </ol>
    <li><a href="#precedence-and-feasibility"><span class="secno">4</span> <span class="content">Precedence and Feasibility</span></a>
    <li>
     <a href="#holistic-view"><span class="secno">5</span> <span class="content">Holistic View</span></a>
     <ol class="toc">
      <li><a href="#2015-lenexa-ewg-discussion-on-n4356"><span class="secno">5.1</span> <span class="content">2015-Lenexa EWG discussion on N4356</span></a>
      <li><a href="#analysis-with-respect-to-n4700-working-draft"><span class="secno">5.2</span> <span class="content">Analysis with respect to N4700 working draft</span></a>
      <li><a href="#type-deduction-non-issue"><span class="secno">5.3</span> <span class="content">Type Deduction Non-Issue</span></a>
      <li><a href="#array-types-of-zero-length"><span class="secno">5.4</span> <span class="content">Array Types of Zero Length</span></a>
      <li><a href="#other-potential-applications"><span class="secno">5.5</span> <span class="content">Other Potential Applications</span></a>
     </ol>
    <li>
     <a href="#references"><span class="secno"></span> <span class="content">References</span></a>
     <ol class="toc">
      <li><a href="#informative"><span class="secno"></span> <span class="content">Informative References</span></a>
     </ol>
   </ol>
  </nav>
  <main>
   <h2 class="heading settled" data-level="1" id="revision-history"><span class="secno">1. </span><span class="content">Revision History</span><a class="self-link" href="#revision-history"></a></h2>
   <h3 class="heading settled" data-level="1.1" id="n4356--original-proposal-2015-lenexa"><span class="secno">1.1. </span><span class="content"><a data-link-type="biblio" href="#biblio-n4356">[N4356]</a> : Original proposal, 2015-Lenexa</span><a class="self-link" href="#n4356--original-proposal-2015-lenexa"></a></h3>
   <h3 class="heading settled" data-level="1.2" id="p0332r0"><span class="secno">1.2. </span><span class="content"><a data-link-type="biblio" href="#biblio-p0332r0">[P0332r0]</a></span><a class="self-link" href="#p0332r0"></a></h3>
   <ul>
    <li data-md="">
     <p>Relaxed array declaration extracted from <a data-link-type="biblio" href="#biblio-p0009r0">[P0009r0]</a></p>
   </ul>
   <h3 class="heading settled" data-level="1.3" id="p0332r1"><span class="secno">1.3. </span><span class="content"><a data-link-type="biblio" href="#biblio-p0332r1">[P0332r1]</a></span><a class="self-link" href="#p0332r1"></a></h3>
   <ul>
    <li data-md="">
     <p>Align with updates to <a data-link-type="biblio" href="#biblio-p0009r3">[P0009r3]</a></p>
    <li data-md="">
     <p>Add examples of precedents</p>
    <li data-md="">
     <p>Reviews at 2017-Albuquerque</p>
     <ul>
      <li data-md="">
       <p>LEWG: moves <a data-link-type="biblio" href="#biblio-p0009r0">[P0009r0]</a> to LWG</p>
      <li data-md="">
       <p>EWG feedback: <a data-link-type="biblio" href="#biblio-p0332r1">[P0332r1]</a> fails to address concerns raised at
2015-Lenexa regarding N4356</p>
     </ul>
   </ul>
   <h3 class="heading settled" data-level="1.4" id="p0332r2"><span class="secno">1.4. </span><span class="content">P0332r2</span><a class="self-link" href="#p0332r2"></a></h3>
   <ul>
    <li data-md="">
     <p>Fully address scope of 2015-Lenexa EWG feedback on <a data-link-type="biblio" href="#biblio-n4356">[N4356]</a></p>
    <li data-md="">
     <p>Introduce clarification for loosely defined <em>incomplete type</em></p>
   </ul>
   <h2 class="heading settled" data-level="2" id="motivation"><span class="secno">2. </span><span class="content">Motivation</span><a class="self-link" href="#motivation"></a></h2>
   <h3 class="heading settled" data-level="2.1" id="array-type-for-mdspan"><span class="secno">2.1. </span><span class="content">Array type for <code class="highlight"><span class="n">mdspan</span></code></span><a class="self-link" href="#array-type-for-mdspan"></a></h3>
   <p>The dimensions of multidimensional array reference <code class="highlight"><span class="n">mdspan</span></code> (<a data-link-type="biblio" href="#biblio-p0331r0">[P0331r0]</a> and <a data-link-type="biblio" href="#biblio-p0009r3">[P0009r3]</a>) are declared with a syntactically verbose
extents property argument.
We propose a minor, non-breaking relaxation of the array type declaration
in [decl.array] to allow a concise and intuitive syntax for
multidimensional declarations.</p>
<pre class="highlight"><span class="k">template</span><span class="o">&lt;</span> <span class="k">typename</span> <span class="n">DataType</span> <span class="p">,</span> <span class="k">typename</span> <span class="n">Properties</span><span class="p">...</span> <span class="o">></span>
<span class="k">struct</span> <span class="n">mdspan</span> <span class="p">;</span>

<span class="c1">// Three dimensional tensor type declaration with</span>
<span class="c1">// verbose syntax and left-to-right increasing stride.</span>
<span class="c1"></span>
<span class="k">using</span> <span class="n">tensor</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">double</span><span class="p">,</span><span class="n">std</span><span class="o">::</span><span class="n">extents</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">dynamic_extent</span><span class="p">,</span><span class="n">std</span><span class="o">::</span><span class="n">dynamic_extent</span><span class="p">,</span><span class="n">std</span><span class="o">::</span><span class="n">dynamic_extent</span><span class="o">></span><span class="p">,</span><span class="n">std</span><span class="o">::</span><span class="n">layout_left</span><span class="o">></span> <span class="p">;</span>

<span class="c1">// Three dimensional tensor type declaration with concise syntax</span>
<span class="c1">// and left-to-right increasing stride.</span>
<span class="c1"></span>
<span class="k">using</span> <span class="n">tensor</span> <span class="o">=</span> <span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">double</span><span class="p">[][][],</span><span class="n">std</span><span class="o">::</span><span class="n">layout_left</span><span class="o">></span> <span class="p">;</span>
</pre>
   <p>The motivating <code class="highlight"><span class="n">mdspan</span></code> multidimensional array library proposal (<a data-link-type="biblio" href="#biblio-p0009r3">[P0009r3]</a>)
was moved by LEWG to LWG in 2017-Albuquerque.
Throughout LEWG discussions of the multidimensional array proposal,
the consensus in LEWG has been that the usability of the <code class="highlight"><span class="n">mdspan</span></code> library would be significantly improved with the relaxed array type
syntax of this proposal.</p>
   <h3 class="heading settled" data-level="2.2" id="why-not"><span class="secno">2.2. </span><span class="content">Why Not</span><a class="self-link" href="#why-not"></a></h3>
<pre class="highlight"><span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">double</span><span class="p">,</span><span class="n">std</span><span class="o">::</span><span class="n">dynamic_extent</span><span class="p">,</span><span class="n">std</span><span class="o">::</span><span class="n">dynamic_extent</span><span class="p">,</span><span class="n">std</span><span class="o">::</span><span class="n">dynamic_extent</span><span class="p">,</span><span class="n">std</span><span class="o">::</span><span class="n">LayoutLeft</span><span class="o">></span>
</pre>
   <ul>
    <li data-md="">
     <p>Does not allow <code class="highlight"><span class="n">layout_left</span></code> or other properties to be types.</p>
    <li data-md="">
     <p>Still requires <code class="highlight"><span class="n">dynamic_extent</span></code> magic number.</p>
   </ul>
   <h3 class="heading settled" data-level="2.3" id="explicit-and-implicit-extents"><span class="secno">2.3. </span><span class="content">Explicit and Implicit Extents</span><a class="self-link" href="#explicit-and-implicit-extents"></a></h3>
   <p>The <code class="highlight"><span class="n">mdspan</span></code> supports declarations with both explicit (compile time)
and implicit (runtime) extents.
Explicit extents enables optimization of array indexing computations
but not all extents can are explicitly known.
For this reaason the Eigen library defines two dimensional array (matrix) types
where either column or row extents may be explicit.
For higher ranks the mix of explicit and implicit extents becomes
syntactically unwieldy; which may be why n-dimensional arrays in
the TensorFlow library does not provide this capability.</p>
   <h3 class="heading settled" data-level="2.4" id="usability-by-mathematicians-scientists-and-engineers"><span class="secno">2.4. </span><span class="content">Usability by Mathematicians, Scientists, and Engineers</span><a class="self-link" href="#usability-by-mathematicians-scientists-and-engineers"></a></h3>
   <p>Multidimensional arrays are a fundamental mathematical building block
in science and engineering.
As such the FORTRAN programming language created over five decades
ago by this community for this community includes multidimensional
arrays as a fundamental component of the language.
Decades of investment in FORTRAN compiler technology enabled high
levels of optimization for mathematical kernels using nested loops
to operate on multidimensional arrays.</p>
   <p>When the C and C++ languages were created, innovators in the
computational mathematical, scientific, and engineering disciplines
realized the benefits of abstraction-enabling features in these languages.
As such numerous development teams switched from FORTRAN to C++ for
their applications.
However, because C++ did not support multidimensional arrays as
usable and optimizable as those in FORTRAN the
state-of-the-practice became for C++ applications to use C++
for higher level abstractions and call FORTRAN routines for
lower level, performance critical kernels.</p>
   <p>Changes in computational hardware, such as the re-introduction of
wide vector units in CPUs and mainstreaming of GPUs for computing,
created a performance-portability problem; different architectures
require different data layouts to achieve performance.
The proposed multidmensional array library (<a data-link-type="biblio" href="#biblio-p0009r3">[P0009r3]</a>) provides
the mechanism to solve this problem; <code class="highlight"><span class="n">mdspan</span></code> with polymorphic data-layout.
The <code class="highlight"><span class="n">msdpan</span></code> library is an opportunity for C++ to solve the data-layout
problem and reclaim performance parity with FORTRAN.</p>
   <p>The proposed <code class="highlight"><span class="n">mdspan</span></code> library provides the necessary features for
performant and portable multidimensional arrays on diverse modern computional
hardware architectures.
However <code class="highlight"><span class="n">mdspan</span></code> has an usability Achilles heal: the current <code class="highlight"><span class="n">mdspan</span></code> syntax for declaring a multidimensional array type is extremely verbose
and unpalatable to the computational mathematicians, scientists, and engineers
who are the primary users of multidimensional array data structures.
The minor, non-breaking change for relaxed multidimensional array type
declarations in this proposal solves the usability problem by providing <code class="highlight"><span class="n">mdspan</span></code> with a concise, intuitive, and highly usable syntax.</p>
   <h3 class="heading settled" data-level="2.5" id="clarifying-difference-between-array-type-and-array-object-declarations"><span class="secno">2.5. </span><span class="content">Clarifying difference between array type and array object declarations</span><a class="self-link" href="#clarifying-difference-between-array-type-and-array-object-declarations"></a></h3>
   <p>An array object has the unusual ability to change array type,
as illustrated in the following example.</p>
<pre class="highlight">  <span class="k">extern</span> <span class="kt">int</span> <span class="n">x</span><span class="p">[];</span>
  <span class="k">using</span> <span class="n">T_incomplete</span> <span class="o">=</span> <span class="k">decltype</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
  <span class="kt">int</span> <span class="n">x</span><span class="p">[</span><span class="mi">42</span><span class="p">];</span>
  <span class="k">using</span> <span class="n">T_complete</span> <span class="o">=</span> <span class="k">decltype</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
  <span class="k">static_assert</span><span class="p">(</span> <span class="o">!</span> <span class="n">is_same_v</span><span class="o">&lt;</span><span class="n">T_incomplete</span><span class="p">,</span><span class="n">T_complete</span><span class="o">></span> <span class="p">);</span>
</pre>
   <p>Specifications (<a data-link-type="biblio" href="#biblio-n4700">[N4700]</a>) to support this unusual ability
conflate the rules for array type and array object declarations.
In this proposal we systematically reviewed complete array type,
incomplete array type, and array object declaration rules in (<a data-link-type="biblio" href="#biblio-n4700">[N4700]</a>)
and propose revisions to disambiguate these rules.</p>
   <h2 class="heading settled" data-level="3" id="proposal"><span class="secno">3. </span><span class="content">Proposal</span><a class="self-link" href="#proposal"></a></h2>
   <p>This proposal has two themes: (1) clarification of incomplete types,
array type declarations, and array object declarations and (2)
relaxation of extent expressions for incomplete array types
but not array object declarations.</p>
   <h3 class="heading settled" data-level="3.1" id="clarification-of-incomplete-types"><span class="secno">3.1. </span><span class="content">Clarification of incomplete types</span><a class="self-link" href="#clarification-of-incomplete-types"></a></h3>
   <p><strong>N4700: [types.basic] 6.9 Types, p5-p6</strong></p>
   <blockquote>
     A class that has been declared but not defined, an enumeration type in
certain contexts (10.2), or an array of unknown bound or of incomplete
element type, is an incompletely-defined object type.
Incompletely-defined object types and cv void are incomplete types
(6.9.1). Objects shall not be defined to have an incomplete type. 
    <p>A class type (such as "class X") might be incomplete at one point in a
translation unit and complete later on; the type "class X" is the same
type at both points. The declared type of an array object might be an
array of incomplete class type and therefore incomplete; if the class
type is completed later on in the translation unit, the array type
becomes complete; the array type at those two points is the same type.
The declared type of an array object might be an array of unknown
bound and therefore be incomplete at one point in a translation unit
and complete later on; the array types at those two points ("array of
unknown bound of T" and "array of N T") are different types. The type
of a pointer to array of unknown bound, or of a type defined by a
typedef declaration to be an array of unknown bound, cannot be
completed.</p>
   </blockquote>
   <p><strong>Proposed: [types.basic] 6.9 Types, p5-p6</strong></p>
   <blockquote>
    <p>An <em>incomplete class type</em> is a class that has been declared but not
defined. A class type (such as "<code class="highlight"><span class="k">class</span> <span class="nc">X</span></code>") might be incomplete at
one point in a translation unit and completed later in the translation
unit; the type "<code class="highlight"><span class="k">class</span> <span class="nc">X</span></code>" is the same type at both points.</p>
    <p>When the element type <code class="highlight"><span class="n">T</span></code> of an "array of <code class="highlight"><span class="n">N</span> <span class="n">T</span></code>" (such as
"<code class="highlight"><span class="n">T</span><span class="p">[</span><span class="n">N</span><span class="p">]</span></code>") is an incomplete class type the array type is incomplete;
if the class type is later completed in the translation unit the array
type becomes complete and the array type at those two points is the
same type.</p>
    <p>When the declared type of an array object is of unknown bound (such as
"<code class="highlight"><span class="n">T</span> <span class="n">obj</span><span class="p">[]</span></code>") at one point in a translation unit and is later
completed in the translation unit (such as "<code class="highlight"><span class="n">T</span> <span class="n">obj</span><span class="p">[</span><span class="n">N</span><span class="p">]</span></code>") the array
types at those two points ("<code class="highlight"><span class="n">T</span><span class="p">[]</span></code>" and "<code class="highlight"><span class="n">T</span><span class="p">[</span><span class="n">N</span><span class="p">]</span></code>") are different
types.</p>
    <p>The type of a pointer to array of unknown bound, or of a type defined
to be an array of unknown bound, cannot be completed.</p>
    <p>Restrictions on the element type <code class="highlight"><span class="n">T</span></code> for an "array of <code class="highlight"><span class="n">N</span> <span class="n">T</span></code>" and
"array of unknown bound of <code class="highlight"><span class="n">T</span></code>" are specified in 11.3.4, Arrays.</p>
    <p>An <em>incompletely-defined object type</em> is</p>
    <ul>
     <li data-md="">
      <p>an incomplete class type,</p>
     <li data-md="">
      <p>an enumeration type in certain contexts (10.2),</p>
     <li data-md="">
      <p>an array of <code class="highlight"><span class="n">N</span> <span class="n">T</span></code> (11.3.4) where <code class="highlight"><span class="n">T</span></code> is an incomplete class
type, or</p>
     <li data-md="">
      <p>an array of unknown bound of <code class="highlight"><span class="n">T</span></code> (11.3.4) where <code class="highlight"><span class="n">T</span></code> is an object
type.</p>
    </ul>
    <p>An <em>incomplete type that cannot be completed</em> is</p>
    <ul>
     <li data-md="">
      <p><em>cv</em> <code class="highlight"><span class="kt">void</span></code> (6.9.1),</p>
     <li data-md="">
      <p>an array of unknown bound of <code class="highlight"><span class="n">T</span></code>,</p>
     <li data-md="">
      <p>a pointer to an incomplete type that cannot be completed other
than <em>cv</em> <code class="highlight"><span class="kt">void</span></code>, or</p>
     <li data-md="">
      <p>an array of <code class="highlight"><span class="n">T</span></code> where element type <code class="highlight"><span class="n">T</span></code> is an incomplete type
that cannot be completed.</p>
    </ul>
    <p>An <em>incomplete type</em> is</p>
    <ul>
     <li data-md="">
      <p>an incompletely-defined object type or</p>
     <li data-md="">
      <p>an incomplete type that cannot be completed.</p>
    </ul>
   </blockquote>
   <p>Add to example:</p>
<pre class="highlight"><span class="k">typedef</span> <span class="kt">int</span> <span class="n">UNKA</span><span class="p">[];</span>      <span class="c1">// UNKA is an incomplete type</span>
<span class="c1"></span><span class="k">typedef</span> <span class="n">UNKA</span> <span class="n">UNKAA</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>  <span class="c1">// UNKAA is an incomplete type that cannot be completed</span>
<span class="c1"></span><span class="n">UNKA</span>  <span class="n">arrn</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>          <span class="c1">// ill-formed, UNKA cannot be completed</span>
<span class="c1"></span><span class="n">UNKA</span><span class="o">*</span> <span class="n">arrp</span><span class="p">;</span>              <span class="c1">// ill-formed, UNKA* cannot be completed</span>
</pre>
   <p><strong>N4700: [types.basic] 6.9 Types, p8</strong></p>
   <blockquote>
    <p>An object type is a (possibly cv-qualified) type that is not a
function type, not a reference type, and not cv void.</p>
   </blockquote>
   <p><strong>Proposed: [types.basic] 6.9 Types, p8</strong></p>
   <blockquote>
    <p>An <em>object type</em> is a (possibly cv-qualified) type that is not a
function type, not a reference type, and not an incomplete type that
cannot be completed.</p>
   </blockquote>
   <h3 class="heading settled" data-level="3.2" id="clarification-and-relaxation-of-array-type"><span class="secno">3.2. </span><span class="content">Clarification and relaxation of array type</span><a class="self-link" href="#clarification-and-relaxation-of-array-type"></a></h3>
   <p><strong>N4700: [dcl.array] 11.3.4 Arrays, p1</strong></p>
   <blockquote>
     In a declaration <code class="highlight"><span class="n">T</span> <span class="n">D</span></code> where <code class="highlight"><span class="n">D</span></code> has the form 
    <p><code class="highlight"><span class="n">D1</span> <span class="p">[</span> <em><span class="n">constant</span><span class="o">-</span><span class="n">expression_opt</span> </em><span class="p">]</span> <br> <em><span class="n">attribute</span><span class="o">-</span><span class="n">specifier</span><span class="o">-</span><span class="n">seq_opt</span> </em></code></p>
    <p>and the type of the identifier in the declaration T D1 is
"derived-declarator-type-list T", then the type of the identifier of D
is an array type; if the type of the identifier of D contains the auto
type-specifier, the program is ill-formed. T is called the array
element type; this type shall not be a reference type, cv void, a
function type or an abstract class type. If the constant-expression
(8.20) is present, it shall be a converted constant expression of type <code class="highlight"><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span></code> and its value shall be greater than zero. The constant
expression specifies the bound of (number of elements in) the array.
If the value of the constant expression is N, the array has N elements
numbered 0 to N-1, and the type of the identifier of D is
"derived-declarator-type-list array of N T". An object of array type
contains a contiguously allocated non-empty set of N subobjects of
type T. Except as noted below, if the constant expression is omitted,
the type of the identifier of D is "derived-declarator-type-list array
of unknown bound of T", an incomplete object type. The type
"derived-declarator-type-list array of N T" is a different type from
the type "derived-declarator-type-list array of unknown bound of T",
see 6.9. Any type of the form "cv-qualifier-seq array of N T" is
adjusted to "array of N cv-qualifier-seq T", and similarly for "array
of unknown bound of T". The optional attribute-specifier-seq
appertains to the array.</p>
   </blockquote>
   <p><strong>Proposed: [dcl.array] 11.3.4 Arrays, p1</strong>; Clarify the difference
between an <em>array type declaration</em> and <em>array object declaration</em>.</p>
   <blockquote>
     In an <em>array type declaration</em> 
    <p><code class="highlight"><span class="n">T</span><span class="p">[</span> <em><span class="n">constant</span><span class="o">-</span><span class="n">expression_opt</span> </em><span class="p">]</span> <br><span class="k">typedef</span> <span class="n">T</span> <span class="n">D1</span> <span class="p">[</span> <em><span class="n">constant</span><span class="o">-</span><span class="n">expression_opt</span> </em><span class="p">]</span> <br><span class="k">using</span> <span class="n">D1</span> <span class="o">=</span> <span class="n">T</span> <span class="p">[</span> <em><span class="n">constant</span><span class="o">-</span><span class="n">expression_opt</span> </em><span class="p">]</span> </code></p>
    <p><code class="highlight"><span class="n">T</span></code> is the array <em>element type</em>; this type shall not be a reference
type, a function type, an abstract class, or <em>cv</em> void. If the <em>constant-expression</em> (8.20) is present, it is a converted constant
expression of type <code class="highlight"><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span></code>. If the value of the constant
expression is <code class="highlight"><span class="n">N</span></code>, the array type is "<em>array of</em> <code class="highlight"><span class="n">N</span> <span class="n">T</span></code>". The
constant expression specifies the <em>bound</em> of (number of elements in)
objects of the array type. If the constant expression is omitted the
type is an "<em>array of unknown bound of</em> <code class="highlight"><span class="n">T</span></code>" and is an incomplete
type (6.9). The type "array of <code class="highlight"><span class="n">N</span> <span class="n">T</span></code>" is a different type from the
type "array of unknown bound of <code class="highlight"><span class="n">T</span></code>" (6.9). Any type of the form
"<em>cv-qualifier-seq</em> array of <code class="highlight"><span class="n">N</span> <span class="n">T</span></code>" is adjusted to "array of <code class="highlight"><span class="n">N</span></code> <em>cv-qualifier-seq</em> <code class="highlight"><span class="n">T</span></code>", similarly for "array of unknown bound of <code class="highlight"><span class="n">T</span></code>". If the element type is an incomplete type that cannot be
completed or an <em>array of unknown bound of U</em>, where <code class="highlight"><span class="n">U</span></code> is any type,
then the array type is an incomplete type that cannot be completed.</p>
    <p>In an <em>array object declaration</em> <code class="highlight"><span class="n">T</span> <span class="n">D</span></code> where <code class="highlight"><span class="n">D</span></code> has the form</p>
    <p><code class="highlight"><span class="n">D1</span> <span class="p">[</span> <em><span class="n">constant</span><span class="o">-</span><span class="n">expression_opt</span> </em><span class="p">]</span> <br> <em><span class="n">attribute</span><span class="o">-</span><span class="n">specifier</span><span class="o">-</span><span class="n">seq_opt</span> </em></code></p>
    <p>and the type of the identifier in the declaration <code class="highlight"><span class="n">T</span> <span class="n">D1</span></code> is
"<em>derived-declarator-type-list</em> <code class="highlight"><span class="n">T</span></code>", then the type of the identifier <code class="highlight"><span class="n">D</span></code> is an array type <code class="highlight"><span class="n">T</span><span class="p">[</span></code><em>constant-expression_opt</em><code class="highlight"><span class="p">]</span></code>. If the type
of the identifier of D contains the auto type-specifier, the program
is ill-formed. <code class="highlight"><span class="n">T</span></code> is called the array <em>element type</em>; this type shall
not be a reference type, a function type, an abstract class, or an
incomplete type that cannot be completed. Except as noted below, the
constant expression shall not be omitted. The optional <em>attribute-specifier-seq</em> appertains to the array object. If the value
of the constant expression is N, the array has N elements numbered 0
to N-1, and the type of the identifier of D is
"<em>derived-declarator-type-list</em> array of <code class="highlight"><span class="n">N</span> <span class="n">T</span></code>". An array object
contains a contiguous non-empty set of <code class="highlight"><span class="n">N</span></code> subobjects of type <code class="highlight"><span class="n">T</span></code> numbered <code class="highlight"><span class="mi">0</span></code> to <code class="highlight"><span class="n">N</span><span class="o">-</span><span class="mi">1</span></code>.</p>
   </blockquote>
   <p><strong>N4700: [dcl.array] 11.3.4 Arrays, p2</strong></p>
   <blockquote>
    <p>An array can be constructed from one of the fundamental types (except
void), from a pointer, from a pointer to member, from a class, from an
enumeration type, or from another array.</p>
   </blockquote>
   <p><strong>Proposed: [dcl.array] 11.3.4 Arrays, p2</strong></p>
   <blockquote>
    <p>An array type can be declared with element type of one of the
fundamental types (except void), a pointer, a pointer to member, a
class, an enumeration type, or another array type.</p>
    <p>An array object can be declared with any array type except one that is
an incomplete type that cannot be completed.</p>
   </blockquote>
   <p><strong>N4700: [dcl.array] 11.3.4 Arrays, p3</strong></p>
   <blockquote>
    <p>When several "array of" specifications are adjacent, a
multidimensional array type is created; only the first of the constant
expressions that specify the bounds of the arrays may be omitted. In
addition to declarations in which an incomplete object type is
allowed, an array bound may be omitted in some cases in the
declaration of a function parameter (11.3.5). An array bound may also
be omitted when the declarator is followed by an initializer (11.6) or
when a declarator for a static data member is followed by a
brace-or-equal-initializer (12.2). In both cases the bound is
calculated from the number of initial elements (say, N) supplied
(11.6.1), and the type of the identifier of D is "array of N T".
Furthermore, if there is a preceding declaration of the entity in the
same scope in which the bound was specified, an omitted array bound is
taken to be the same as in that earlier declaration, and similarly for
the definition of a static data member of a class.</p>
   </blockquote>
   <p><strong>Proposed: [dcl.array] 11.3.4 Arrays, p3</strong></p>
   <blockquote>
    <p>When several "array of" specifications are adjacent, a
multidimensional array type is created. In declarations in which an <em>incomplete type</em> is allowed any of the constant expressions that
specify the bounds of the arrays may be omitted; if any of the
constant expressions are omitted the type is an incomplete type that
cannot be completed. The first of the constant expressions that specify
the bounds of the arrays may be omitted</p>
    <ul>
     <li data-md="">
      <p>in some cases in the declaration of a function parameter
(11.3.5),</p>
     <li data-md="">
      <p>when the declarator is followed by an initializer (11.6),</p>
     <li data-md="">
      <p>when a declarator for a static data member is followed by a
brace-or-equal-initializer (12.2), or</p>
     <li data-md="">
      <p>if there is a preceding declaration of the entity in the same
scope in which the bound was specified.</p>
    </ul>
    <p>In the initializer cases the bound is calculated from the number of
initial elements (say, N) supplied (11.6.1), and the type of the
identifier of D is "array of N T". In the preceding declaration case
an omitted array bound is taken to be the same as in that earlier
declaration, and similarly for the definition of a static data member
of a class.</p>
   </blockquote>
   <h3 class="heading settled" data-level="3.3" id="type_traits-interaction"><span class="secno">3.3. </span><span class="content">type_traits interaction</span><a class="self-link" href="#type_traits-interaction"></a></h3>
<pre class="highlight"><span class="k">using</span> <span class="n">S</span> <span class="o">=</span> <span class="kt">double</span><span class="p">[</span><span class="mi">10</span><span class="p">][</span><span class="mi">20</span><span class="p">][]</span> <span class="p">;</span>
<span class="n">rank_v</span><span class="o">&lt;</span><span class="n">S</span><span class="o">></span> <span class="o">==</span> <span class="mi">3</span>
<span class="n">extent_v</span><span class="o">&lt;</span><span class="n">S</span><span class="p">,</span><span class="mi">0</span><span class="o">></span> <span class="o">==</span> <span class="mi">10</span>
<span class="n">extent_v</span><span class="o">&lt;</span><span class="n">S</span><span class="p">,</span><span class="mi">1</span><span class="o">></span> <span class="o">==</span> <span class="mi">20</span>
<span class="n">extent_v</span><span class="o">&lt;</span><span class="n">S</span><span class="p">,</span><span class="mi">2</span><span class="o">></span> <span class="o">==</span> <span class="mi">0</span>

<span class="n">remove_extent_t</span><span class="o">&lt;</span><span class="n">S</span><span class="o">></span> <span class="c1">// is an incomplete type</span>
<span class="c1"></span><span class="n">is_same_v</span><span class="o">&lt;</span> <span class="n">remove_extent_t</span><span class="o">&lt;</span><span class="n">S</span><span class="o">></span> <span class="p">,</span> <span class="kt">double</span><span class="p">[</span><span class="mi">20</span><span class="p">][]</span> <span class="o">></span>

<span class="n">remove_extent_t</span><span class="o">&lt;</span> <span class="n">remove_extent_t</span><span class="o">&lt;</span><span class="n">S</span><span class="o">></span> <span class="o">></span> <span class="c1">// is an incomplete type</span>
<span class="c1"></span><span class="n">is_same_v</span><span class="o">&lt;</span> <span class="n">remove_extent_t</span><span class="o">&lt;</span> <span class="n">remove_extent_t</span><span class="o">&lt;</span><span class="n">S</span><span class="o">></span> <span class="o">></span> <span class="p">,</span> <span class="kt">double</span><span class="p">[]</span> <span class="o">></span>

<span class="n">decay_t</span><span class="o">&lt;</span><span class="n">S</span><span class="o">></span> <span class="c1">// is an incomplete type</span>
<span class="c1"></span><span class="n">is_same_v</span><span class="o">&lt;</span> <span class="n">decay_t</span><span class="o">&lt;</span><span class="n">S</span><span class="o">></span> <span class="p">,</span> <span class="kt">double</span><span class="p">(</span><span class="o">*</span><span class="p">)[</span><span class="mi">20</span><span class="p">][]</span> <span class="o">></span>
</pre>
   <h2 class="heading settled" data-level="4" id="precedence-and-feasibility"><span class="secno">4. </span><span class="content">Precedence and Feasibility</span><a class="self-link" href="#precedence-and-feasibility"></a></h2>
   <p>An incomplete array type <code class="highlight"><span class="n">T</span><span class="p">[]</span></code> to concisely indicate an array of runtime
length is used by <code class="highlight"><span class="n">std</span><span class="o">::</span><span class="n">unique_ptr</span><span class="o">&lt;</span><span class="n">T</span><span class="p">[]</span><span class="o">></span></code> (23.11.1.3), <code class="highlight"><span class="n">std</span><span class="o">::</span><span class="n">shared_ptr</span><span class="o">&lt;</span><span class="n">T</span><span class="o">></span></code> where <code class="highlight"><span class="n">T</span></code> is <code class="highlight"><span class="n">U</span><span class="p">[]</span></code> (23.11.2.2), and <a data-link-type="biblio" href="#biblio-p0674r1">[P0674r1]</a> <code class="highlight"><span class="n">make_shared</span><span class="o">&lt;</span><span class="n">T</span><span class="p">[][</span><span class="n">N1</span><span class="p">][</span><span class="n">N2</span><span class="p">]</span><span class="o">></span></code>.</p>
   <p>This minor language specification change has been implemented with a
simple patch to Clang.</p>
   <h2 class="heading settled" data-level="5" id="holistic-view"><span class="secno">5. </span><span class="content">Holistic View</span><a class="self-link" href="#holistic-view"></a></h2>
   <h3 class="heading settled" data-level="5.1" id="2015-lenexa-ewg-discussion-on-n4356"><span class="secno">5.1. </span><span class="content">2015-Lenexa EWG discussion on N4356</span><a class="self-link" href="#2015-lenexa-ewg-discussion-on-n4356"></a></h3>
   <blockquote>
    <p>"Stepping back for a second, I think this is a small change but
there are a whole bunch of ways of constructing types and we disallow
many because they would give uninhabited types. But then look at <code class="highlight"><span class="n">std</span><span class="o">::</span><span class="n">result_of</span></code>, after this change you can use <code class="highlight"><span class="n">std</span><span class="o">::</span><span class="n">result_of</span></code> on a
whole bunch of types, but not on a function type (ironically). I think
there may be some sense in this, I’d like to see some more holistic
view of this, I don’t want to see pointers or references to these, or
functions declared with these things as arguments."</p>
   </blockquote>
   <h3 class="heading settled" data-level="5.2" id="analysis-with-respect-to-n4700-working-draft"><span class="secno">5.2. </span><span class="content">Analysis with respect to N4700 working draft</span><a class="self-link" href="#analysis-with-respect-to-n4700-working-draft"></a></h3>
   <p>Let <code class="highlight"><span class="n">S</span></code> be an incomplete multdimensional array type greater than rank 1
from which an extent other than the leading extent is ommitted.</p>
   <p><strong>N4700 [basic.link] 6.5 Program and linkage, p10</strong></p>
   <blockquote>
    <p>After all adjustments of types (during which typedefs (10.1.3) are
replaced by their definitions), the types specified by all
declarations referring to a given variable or function shall be
identical, except that declarations for an array object can specify
array types that differ by the presence or absence of a major array
bound (11.3.4). A violation of this rule on type identity does not
require a diagnostic.</p>
   </blockquote>
   <p>Array object declarations restricted to absence of only the leading
array bound.</p>
   <p><strong>N4700 [types.basic] 6.9 Types, p5</strong></p>
   <blockquote>
    <p><strong>incompletely-defined object type</strong></p>
    <p>A class that has been declared but not defined, an enumeration type
in certain contexts (10.2), or an array of unknown bound or of
incomplete element type, is an incompletely-defined object type.
Incompletely-defined object types and cv void are incomplete types
(6.9.1). Objects shall not be defined to have an incomplete type.</p>
    <p>[footnote] The size and layout of an instance of an
incompletely-defined object type is unknown.</p>
   </blockquote>
   <p>An array of unknown bound is an incomplete type, so <code class="highlight"><span class="n">S</span></code> can never be
used to declare an object.</p>
   <p><strong>N4700 [types.basic] 6.9 Types, p6</strong></p>
   <blockquote>
    <p>The declared type of an array object might be an array of unknown
bound and therefore be incomplete at one point in a translation unit
and complete later on; the array types at those two points ("array of
unknown bound of T" and "array of N T") are different types. The type
of a pointer to array of unknown bound, or of a type defined by a
typedef declaration to be an array of unknown bound, cannot be
completed.</p>
   </blockquote>
   <p>The type of a pointer to <code class="highlight"><span class="n">S</span></code> is an incomplete type that cannot be
completed and therefore can never be used to declare an object.</p>
   <p><strong>N4700 [basic.fundamental] 6.9.1 Fundamental types, p9</strong></p>
   <blockquote>
    <p>A type cv void is an incomplete type that cannot be completed; such a
type has an empty set of values.</p>
   </blockquote>
   <p>An incomplete multidimensional array type in which an extent other than
the first extent is ommitted cannot be completed.</p>
   <p><strong>N4700 [basic.type.qualifier] 6.9.3 CV-qualifiers, p1</strong></p>
   <blockquote>
    <p>Each type which is a cv-unqualified complete or incomplete object
type or is void (6.9)...</p>
   </blockquote>
   <p>CV-qualifiers apply to complete or incomplete types.</p>
   <p><strong>N4700 [conf.array] 7.2 Array-to-pointer conversion</strong></p>
   <blockquote>
    <p>An lvalue or rvalue of type "array of N T" or "array of unknown bound
of T" can be converted to a prvalue of type "pointer to T". The
temporary materialization conversion (7.4) is applied. The result is a
pointer to the first element of the array.</p>
   </blockquote>
   <p>As is, <code class="highlight"><span class="n">T</span></code> cannot be an <em>incomplete type that cannot be completed</em>, such
as <code class="highlight"><span class="kt">void</span></code>. This proposal does not change this fact.</p>
   <p><strong>N4700 [conv.rval] 7.4 Temporary materialization conversion
[conv.rval]</strong></p>
   <blockquote>
    <p>A prvalue of type T can be converted to an xvalue of type T. This
conversion initializes a temporary object (15.2) of type T from the
prvalue by evaluating the prvalue with the temporary object as its
result object, and produces an xvalue denoting the temporary object. T
shall be a complete type.</p>
   </blockquote>
   <p>The decay of <code class="highlight"><span class="kt">int</span><span class="p">[][</span><span class="n">M</span><span class="p">][]</span></code> is <code class="highlight"><span class="kt">int</span><span class="p">(</span><span class="o">*</span><span class="p">)[</span><span class="n">M</span><span class="p">][]</span></code> which is an incomplete type
that cannot be completed, and objects cannot be declared of this type.
Therefore converting <code class="highlight"><span class="kt">int</span><span class="p">[][</span><span class="n">M</span><span class="p">][]</span></code> to a pointer is an error.</p>
   <p><strong>N4700 [expr.call] 8.2.2 Function call, p4</strong></p>
   <blockquote>
    <p>When a function is called, the parameters that have object type shall
have completely-defined object type. [Note: this still allows a
parameter to be a pointer or reference to an incomplete class type.
However, it prevents a passed-by-value parameter to have an incomplete
class type. ---end note]</p>
   </blockquote>
   <p>A parameter is not allowed to be a pointer or reference to an incomplete
array type.</p>
   <p><strong>N4700 [expr.throw] 8.17 Throwing an exception, p2</strong></p>
   <blockquote>
    <p>Evaluating a throw-expression with an operand throws an exception
(18.1); the type of the exception object is determined by removing any
top-level cv-qualifiers from the static type of the operand and
adjusting the type from "array of T" or function type T to "pointer to
T".</p>
   </blockquote>
   <p><strong>N4700 [dcl.array] 11.3.4 Arrays, p2</strong></p>
   <blockquote>
    <p>An array can be constructed from one of the fundamental types (except
void), from a pointer, from a pointer to member, from a class, from an
enumeration type, or from another array.</p>
   </blockquote>
   <p>"Another array" may be an array of unknown bound.</p>
   <p><strong>N4700 [dlc.fct] 11.3.5 Functions, p5</strong></p>
   <blockquote>
    <p>After determining the type of each parameter, any parameter of type
"array of T" or of function type T is adjusted to be "pointer to T".</p>
   </blockquote>
   <p>Constrain such that T is a complete type or an incomplete class type.</p>
   <p><strong>N4700 [dcl.stc] Storage class specifiers, p7</strong></p>
   <blockquote>
    <p>The name of a declared but undefined class can be used in an extern
declaration. Such a declaration can only be used in ways that do not
require a complete class type.</p>
   </blockquote>
   <p>Incomplete array types cannot be used as the return type of a function.</p>
   <h3 class="heading settled" data-level="5.3" id="type-deduction-non-issue"><span class="secno">5.3. </span><span class="content">Type Deduction Non-Issue</span><a class="self-link" href="#type-deduction-non-issue"></a></h3>
   <p>Incomplete array types observe normal type deduction and pointer decay rules.</p>
<pre class="highlight"><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
<span class="kt">void</span> <span class="n">f</span><span class="p">(</span> <span class="n">mdspan</span><span class="o">&lt;</span><span class="n">T</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="mi">5</span><span class="p">]</span><span class="o">></span> <span class="p">);</span> <span class="c1">// A</span>
<span class="c1"></span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
<span class="kt">void</span> <span class="n">f</span><span class="p">(</span> <span class="n">mdspan</span><span class="o">&lt;</span><span class="n">T</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">3</span><span class="p">][</span><span class="mi">5</span><span class="p">]</span><span class="o">></span> <span class="p">);</span> <span class="c1">// B</span>
<span class="c1"></span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
<span class="kt">void</span> <span class="n">f</span><span class="p">(</span> <span class="n">mdspan</span><span class="o">&lt;</span><span class="n">T</span><span class="p">[</span><span class="mi">1</span><span class="p">][][</span><span class="mi">5</span><span class="p">]</span><span class="o">></span> <span class="p">);</span> <span class="c1">// C</span>
<span class="c1"></span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">M</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">N</span><span class="o">></span>
<span class="kt">void</span> <span class="n">f</span><span class="p">(</span> <span class="n">mdspan</span><span class="o">&lt;</span><span class="n">T</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">M</span><span class="p">][]</span><span class="o">></span> <span class="p">)</span> <span class="c1">// D</span>
<span class="c1"></span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">M</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">N</span><span class="o">></span>
<span class="kt">void</span> <span class="n">f</span><span class="p">(</span> <span class="n">mdspan</span><span class="o">&lt;</span><span class="n">T</span><span class="p">[][</span><span class="n">N</span><span class="p">][</span><span class="n">M</span><span class="p">]</span><span class="o">></span> <span class="p">);</span> <span class="c1">// E</span>
<span class="c1"></span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
<span class="kt">void</span> <span class="n">f</span><span class="p">(</span> <span class="n">T</span><span class="p">[][</span><span class="mi">3</span><span class="p">][</span><span class="mi">5</span><span class="p">]</span> <span class="p">);</span> <span class="c1">// F</span>
<span class="c1"></span>  <span class="c1">// adjusted to pointer T(*)[3][5]</span>
<span class="c1"></span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">></span>
<span class="kt">void</span> <span class="n">f</span><span class="p">(</span> <span class="n">T</span><span class="p">[][][</span><span class="mi">5</span><span class="p">]</span> <span class="p">);</span> <span class="c1">// G</span>
<span class="c1"></span>  <span class="c1">// adjusted to pointer T(*)[][5] which is</span>
<span class="c1"></span>  <span class="c1">// invalid due to T[][5] incomplete array type</span>
<span class="c1"></span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">M</span> <span class="o">></span>
<span class="kt">void</span> <span class="n">f</span><span class="p">(</span> <span class="n">T</span><span class="p">[][</span><span class="n">M</span><span class="p">][]</span> <span class="p">)</span> <span class="c1">// H</span>
<span class="c1"></span>  <span class="c1">// adjusted to pointer T(*)[M][] which is</span>
<span class="c1"></span>  <span class="c1">// invalid due to T[][5] incomplete array type</span>
<span class="c1"></span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">M</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">N</span><span class="o">></span>
<span class="kt">void</span> <span class="n">f</span><span class="p">(</span> <span class="n">T</span><span class="p">[][</span><span class="n">N</span><span class="p">][</span><span class="n">M</span><span class="p">]</span> <span class="p">);</span> <span class="c1">// I</span>
<span class="c1"></span>  <span class="c1">// adjusted to pointer T(*)[M][N]</span>
<span class="c1"></span>

<span class="kt">int</span> <span class="nf">foo</span><span class="p">(</span> <span class="n">mdspan</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">3</span><span class="p">][</span><span class="mi">5</span><span class="p">]</span><span class="o">></span> <span class="n">x</span> <span class="p">)</span>
<span class="p">{</span>
  <span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">);</span> <span class="c1">// no ambiquity</span>
<span class="c1"></span>  <span class="c1">// COULD match A with T == int[1]</span>
<span class="c1"></span>  <span class="c1">// DOES  match B with T == int ; more specialized</span>
<span class="c1"></span>  <span class="c1">// NOT match D because [3] != []</span>
<span class="c1"></span>  <span class="c1">// NOT match E because [5] != []</span>
<span class="c1"></span>  <span class="c1">// NOT match F because [1] != []</span>
<span class="c1"></span><span class="p">}</span>

<span class="kt">int</span> <span class="nf">foo</span><span class="p">(</span> <span class="kt">int</span> <span class="n">y</span><span class="p">[][</span><span class="mi">3</span><span class="p">][</span><span class="mi">5</span><span class="p">]</span> <span class="p">)</span>
<span class="p">{</span>
  <span class="n">f</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
  <span class="c1">// DOES match F ; more specialized</span>
<span class="c1"></span>  <span class="c1">// COULD match I </span>
<span class="c1"></span><span class="p">}</span>
</pre>
   <h3 class="heading settled" data-level="5.4" id="array-types-of-zero-length"><span class="secno">5.4. </span><span class="content">Array Types of Zero Length</span><a class="self-link" href="#array-types-of-zero-length"></a></h3>
   <p>An array type of zero length <code class="highlight"><span class="kt">int</span><span class="p">[</span><span class="n">M</span><span class="p">][</span><span class="n">N</span><span class="p">]</span></code> where <code class="highlight"><span class="n">N</span><span class="o">==</span><span class="mi">0</span></code> is invalid.
This can lead to challenges in meta-programming where <code class="highlight"><span class="n">N</span></code> is computed.
A potential work-around enabled by this proposal is to map such a type
to an incomplete type.</p>
<pre class="highlight">  <span class="k">template</span><span class="o">&lt;</span> <span class="kt">size_t</span> <span class="n">M</span> <span class="p">,</span> <span class="kt">size_t</span> <span class="n">N</span> <span class="o">></span>
  <span class="k">using</span> <span class="n">T</span> <span class="o">=</span> <span class="n">conditional_t</span><span class="o">&lt;</span> <span class="n">N</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">,</span> <span class="kt">int</span><span class="p">[</span><span class="n">M</span><span class="p">][</span><span class="n">N</span><span class="o">?</span><span class="nl">N</span><span class="p">:</span><span class="mi">1</span><span class="p">]</span> <span class="p">,</span> <span class="kt">int</span><span class="p">[</span><span class="n">M</span><span class="p">][]</span> <span class="o">></span> <span class="p">;</span>
</pre>
   <h3 class="heading settled" data-level="5.5" id="other-potential-applications"><span class="secno">5.5. </span><span class="content">Other Potential Applications</span><a class="self-link" href="#other-potential-applications"></a></h3>
   <p>There may be other potential applications for the proposed
relaxed incomplete array syntax; for example deduction of
multiple dimensions.</p>
  </main>

		Active content removed
	
  <h2 class="no-num no-ref heading settled" id="references"><span class="content">References</span><a class="self-link" href="#references"></a></h2>
  <h3 class="no-num no-ref heading settled" id="informative"><span class="content">Informative References</span><a class="self-link" href="#informative"></a></h3>
  <dl>
   <dt id="biblio-n4356">[N4356]
   <dd>Carter Edwards. <a href="https://wg21.link/n4356">Relaxed Array Type Declarator</a>. 4 February 2015. URL: <a href="https://wg21.link/n4356">https://wg21.link/n4356</a>
   <dt id="biblio-n4700">[N4700]
   <dd>Richard Smith. <a href="https://wg21.link/n4700">Working Draft, Standard for Programming Language C++ Note:</a>. URL: <a href="https://wg21.link/n4700">https://wg21.link/n4700</a>
   <dt id="biblio-p0009r0">[P0009r0]
   <dd>H. Carter Edwards, Christian Trott, Juan Alday, Jesse Perla, Mauro Bianco, Robin Maffeo, Ben Sander, Bryce Lelbach. <a href="https://wg21.link/p0009r0">Polymorphic Multidimensional Array View</a>. 23 September 2015. URL: <a href="https://wg21.link/p0009r0">https://wg21.link/p0009r0</a>
   <dt id="biblio-p0009r3">[P0009r3]
   <dd>H. Carter Edwards, Bryce Lelbach, Christian Trott, Mauro Bianco, Robin Maffeo, Ben Sander. <a href="https://wg21.link/p0009r3">Polymorphic Multidimensional Array View</a>. 14 October 2016. URL: <a href="https://wg21.link/p0009r3">https://wg21.link/p0009r3</a>
   <dt id="biblio-p0331r0">[P0331r0]
   <dd>H. Carter Edwards, Bryce Lelbach, Christian Trott, Mauro Bianco, Robin Maffeo, Ben Sander. <a href="https://wg21.link/p0331r0">Motivation and Examples for Multidimensional Array</a>. 27 May 2016. URL: <a href="https://wg21.link/p0331r0">https://wg21.link/p0331r0</a>
   <dt id="biblio-p0332r0">[P0332r0]
   <dd>H. Carter Edwards, Bryce Lelbach, Christian Trott, Mauro Bianco, Robin Maffeo, Ben Sander. <a href="https://wg21.link/p0332r0">Relaxed Incomplete Multidimensional Array Type Declaration</a>. 27 May 2016. URL: <a href="https://wg21.link/p0332r0">https://wg21.link/p0332r0</a>
   <dt id="biblio-p0332r1">[P0332r1]
   <dd>H. Carter Edwards, Bryce Lelbach, Christian Trott, Mauro Bianco, Athanasios Iliopoulos, John Michopoulos. <a href="https://wg21.link/p0332r1">Relaxed Incomplete Multidimensional Array Type Declaration</a>. URL: <a href="https://wg21.link/p0332r1">https://wg21.link/p0332r1</a>
   <dt id="biblio-p0674r1">[P0674r1]
   <dd>Peter Dimov, Glen Fernandes. <a href="https://wg21.link/p0674r1">Extending make_shared to Support Arrays</a>. URL: <a href="https://wg21.link/p0674r1">https://wg21.link/p0674r1</a>
  </dl>