<html>
<head>
<title>P0217R3: Wording for structured bindings</title>

<style type="text/css">
  ins { text-decoration:none; font-weight:bold; background-color:#A0FFA0 }
  .new { text-decoration:none; font-weight:bold; background-color:#D0FFD0 }
  .rule { background-color:#FFFF40 }
  .ex { background-color: #D0FFF0 }
  del { text-decoration:line-through; background-color:#FFA0A0 }  
  strong { font-weight: inherit; color: #2020ff }
</style>
</head>

<body>
P0217R3<br/>
Jens Maurer &lt;Jens.Maurer@gmx.net><br/>
Audience: Evolution and Library Evolution Working Groups<br/>
2016-06-24<br/>

<h1>P0217R3: Proposed wording for structured bindings</h1>

<h2>Introduction</h2>

This paper presents the proposed wording to implement structured
bindings as described by Herb Sutter, Bjarne Stroustrup, and Gabriel
dos Reis in P0144R2.  That paper incorporates feedback from the EWG
session in Jacksonville as follows:

<ul>
<li>change to [] syntax</li>

<li>introduced variables are, in all cases, references to the value of
the initializer</li>

<li>the cv-qualifiers and ref-qualifier of the decomposition
declaration are applied to the reference introduced for the
initializer, not for the individual member aliases</li>

<li>support bit-fields</li>

<li>use tuple_size and tuple_element</li>

</ul>

In this paper, changes relative to the predecessor P0217R2 are
highlighted with <strong>blue text</strong>.

<h2>Open issues</h2>

The following issues have been raised in e-mail discussions following
the Jacksonville meeting and might need further EWG and/or LEWG
guidance:

<ul>

<li>Bit-field support only works when a user-supplied get&lt;> is not
involved [Jacksonville EWG guidance: support bit-fields nonetheless]</li>

<li>The use of plain get&lt;>() as a customization point is too
generic a name. Something like tuple_get&lt;>() would be more
specific, and consistent with tuple_size&lt;> and
tuple_element&lt;>.</li>

<li>It would be good if tuple_size&lt;> could be found by
argument-dependent lookup; we currently require specializing a
standard library template for the user type. Counterargument: We also
require std::tuple_element&lt;> to be specialized, and since this
supplies a type, a mapping to a function is not obvious.</li>

<li>Customization of structured bindings for a user-declared type T
requires specializing standard library templates declared in the
&lt;tuple> header, which is not required to be present in a
freestanding implementation (17.6.1.3 [compliance]).  Similar to
initializer lists, the basic library support for a core language
facility should be presented in a header supplied by a freestanding
implementation.</li>

</ul>

As per guidance from EWG, these issues do not change the design of the
current paper as targeted for C++17.


<h2>Wording</h2>

Change in 5.1.1 [expr.prim] paragraph 8:

<blockquote>
... The type of the expression is the type of the identifier.  The
result is the entity denoted by the
identifier. The <del>result</del> <ins>expression</ins> is an lvalue
if the entity is a function, variable, or data member and a prvalue
otherwise<ins>; it is a bit-field if the identifier designates a
bit-field (7.1.6.4 [dcl.spec.auto]).</ins>

</blockquote>


<strong>Change in 5.1.5 [expr.prim.lambda] paragraph 18:</strong>

<blockquote>
... A <ins>bit-field or a</ins> member of an anonymous union shall not
be captured by reference.
</blockquote>


Change in 5.2.5 [expr.ref] paragraph 3:

<blockquote>

Abbreviating <em>postfix-expression</em>.<em>id-expression</em> as
E1.E2, E1 is called the object expression. <ins>If <code>E2</code> is
a bit-field, <code>E1.E2</code> is a bit-field.</ins> ...

</blockquote>

In section 6.5 [stmt.iter] paragraph 1, change the grammar to allow a
decomposition declaration:

<blockquote>
<pre>
<em>for-range-declaration:
      attribute-specifier-seq<sub>opt</sub> decl-specifier-seq declarator</em>
      <ins><em>attribute-specifier-seq</em><sub>opt</sub> <em>decl-specifier-seq</em> <em>ref-qualifier</em><sub>opt</sub> [ <em>identifier-list</em> ]</ins>
</pre>
</blockquote>

In section 7 [dcl.dcl] paragraph 1, change the grammar to allow a
decomposition declaration:

<blockquote>
<pre>
<em>simple-declaration:
      decl-specifier-seq init-declarator-list<sub>opt</sub></em> ;
      <em>attribute-specifier-seq decl-specifier-seq init-declarator-list</em> ;
      <ins><em>attribute-specifier-seq</em><sub>opt</sub> <em>decl-specifier-seq</em> <em>ref-qualifier</em><sub>opt</sub> [ <em>identifier-list</em> ] <em>brace-or-equal-initializer</em> ;</ins>
</pre>
</blockquote>

Add a new paragraph after 7 [dcl.dcl] paragraph 8:

<blockquote class="new">
A <em>simple-declaration</em> with an <em>identifier-list</em> is
called a <em>decomposition declaration</em>. The
<em>decl-specifier-seq</em> shall contain only the
<em>type-specifier</em> <code>auto</code> (7.1.6.4 [dcl.spec.auto])
and <em>cv-qualifier</em>s.  The <em>brace-or-equal-initializer</em>
shall be of the form "= <em>assignment-expression</em>" or of the form
"{ <em>assignment-expression</em> }", where the
<em>assignment-expression</em> is of array or non-union class
type.

</blockquote>

Change in 7.1.6.2 [dcl.type.simple] paragraph 4:

<blockquote>
For an expression e, the type denoted by <code>decltype(e)</code> is
defined as follows:

<ul>

<li><ins>if e is an unparenthesized <em>id-expression</em> naming an
lvalue or reference introduced from the <em>identifier-list</em> of a
decomposition declaration, <code>decltype(e)</code> is the referenced
type as given in the specification of the decomposition declaration
(7.1.6.4 [dcl.spec.auto]);</ins></li>
  
<li><ins>otherwise,</ins> if e is an unparenthesized id-expression or
an unparenthesized class member access (5.2.5), decltype(e) is the
type of the entity named by e. If there is no such entity, or if e
names a set of overloaded functions, the program is ill-formed;</li>

<li>otherwise, if e is an xvalue, decltype(e) is T&&, where T is the
type of e;</li>

<li>otherwise, if e is an lvalue, decltype(e) is T&, where T is the
type of e;</li>
  
<li>otherwise, decltype(e) is the type of e.</li>
</ul>

</blockquote>

<strong>Add in 7.1.6.4 [dcl.spec.auto] paragraph 1:</strong>

<blockquote>
The <code>auto</code>
and <code>decltype(auto)</code> <em>type-specifier</em>s are used to
designate a placeholder type that will be replaced later by deduction
from an initializer. The auto <em>type-specifier</em> is also used to
introduce a function type having a trailing-return-type or to signify
that a lambda is a generic lambda <ins>(5.1.5 [expr.prim.lambda])</ins>.
<ins>The <code>auto</code> <em>type-specifier</em> is also used to
introduce a decomposition declaration (8.5 [dcl.decomp]).</ins>
</blockquote>

Add a new section before 8.5 [dcl.init]:

<blockquote class="new">
<b>8.5 Decomposition declarations [dcl.decomp]</b>
<p>
  
A decomposition declaration introduces the <em>identifier</em>s of the
<em>identifier-list</em> as names in the order of appearance, where
<em>v<sub>i</sub></em> denotes the <em>i</em>-th identifier, with
numbering starting at 1.  Let <em>cv</em> denote the
<em>cv-qualifier</em>s in the <em>decl-specifier-seq</em>. First, a
variable with a unique name <em>e</em> is introduced.  If the
<em>assignment-expression</em> in the
<em>brace-or-equal-initializer</em> has array type A and no
<em>ref-qualifier</em> is present, <code>e</code> has type <em>cv</em>
<code>A</code> and <strong>each element is copy-initialized or
direct-initialized from the corresponding element of the</strong>
<em>assignment-expression</em> as specified by the form of the
<em>brace-or-equal-initializer</em>.

Otherwise, <code>e</code> is defined as-if by

<pre>
  <em>attribute-specifier-seq</em><sub>opt</sub> <em>decl-specifier-seq</em> <em>ref-qualifier</em><sub>opt</sub> <em>e</em> <em>brace-or-equal-initializer</em> ;
</pre>

where the parts of the declaration other than the
<em>declarator-id</em> are taken from the corresponding decomposition
declaration.  The type of the <strong><em>id-expression</em></strong> <code>e</code> is called
<code>E</code>. [ Note: <code>E</code> is never a reference type
(Clause 5 [expr]). -- end note ]

<p>

If <code>E</code> is an array type with element type T, the number of
elements in the <em>identifier-list</em> shall be equal to the number
of elements of <code>E</code>.  Each <em>v<sub>i</sub></em> is the
name of an lvalue that refers to the element <em>i</em>-1 of the array
and whose type is T; the referenced type is T.  [ Note: The top-level
cv-qualifiers of T are <em>cv</em>. -- end note ] <strong>[ Example:
    <pre>
      auto f() -> int(&)[2];
      auto [ x, y ] = f();   // x and y refer to elements in a copy of the array return value
      auto& [ xr, yr ] = f();  // xr and yr refer to elements in the array referred to by f's return value
    </pre>
    -- end example ]</strong>

</li>

<p>
Otherwise, if the expression <code>std::tuple_size&lt;E>::value</code>
is a well-formed integral constant expression, the number of elements
in the <em>identifier-list</em> shall be equal to the value of that
expression.  The <em>unqualified-id</em> <code>get</code> is looked up
in the scope of <code>E</code> by class member access lookup (3.4.5
[basic.lookup.classref]), and if that finds at least one declaration,
the initializer is <code><em>e</em>.get&lt;<em>i</em>-1>()</code>.
Otherwise, the initializer is
<code>get&lt;<em>i</em>-1>(<em>e</em>)</code>, where <code>get</code>
is looked up in the associated namespaces (3.4.2
[basic.lookup.argdep]). <strong>In either
case, <code>get&lt;<em>i</em>-1></code> is taken as
a <em>template-id</em>.</strong> [ Note: Ordinary unqualified
lookup (3.4.1 [basic.lookup.unqual]) is not performed. -- end note ]
In either case,
<code>e</code> is an lvalue if the type of the entity <code>e</code>
is an lvalue reference and an xvalue otherwise.  Given the type
T<sub>i</sub> designated by
<code>std::tuple_element&lt;<em>i</em>-1,E>::type</code>, each
<em>v<sub>i</sub></em> is a variable of type "reference to
T<sub>i</sub>" initialized with the initializer, where the reference
is an lvalue reference if the initializer is an lvalue and an rvalue
reference otherwise; the referenced type is T<sub>i</sub>.

</li>

<p>
Otherwise, all of <code>E</code>'s non-static data members shall be
public direct members of <code>E</code> or of the same unambiguous
public base class of <code>E</code>, <code>E</code> shall not have an
anonymous union member, and the number of elements in
the <em>identifier-list</em> shall be equal to the number of
non-static data members of <code>E</code>.  The <em>i</em>-th
non-static data member of E in declaration order is designated by
<em>m<sub>i</sub></em>.  Each <em>v<sub>i</sub></em> is the name of an
lvalue that refers to the member <em>m<sub>i</sub></em> of
<code>e</code> and whose type is <em>cv</em> T<sub>i</sub>, where
T<sub>i</sub> is the declared type of that member; the referenced type
is <em>cv</em> T<sub>i</sub>.  The lvalue is a bit-field if that
member is a bit-field.

</li>

</ul>

[ Example:
<pre>
struct S { int x1 : 2; volatile double y1; };
S f();
const auto [ x, y ] = f();
</pre>

The type of the <strong><em>id-expression</em></strong> <code>x</code>
is "const int", the type of
the <strong><em>id-expression</em></strong> <code>y</code> is "const
volatile double". -- end example ]

</blockquote>

<strong>Add in 14.6.2.2 [temp.dep.expr] paragraph 3:</strong>

<blockquote>
  An <em>id-expression</em> is type-dependent if it contains
  <ul>
    <li>...</li>
    <li><ins>an <em>identifier</em> associated by name lookup with a
    decomposition declaration (8.5 [dcl.decomp])
    whose <em>brace-or-equal-initializer</em> is
    type-dependent,</ins></li>
    <li>...</li>
  </ul>
  
</blockquote>

</body>
</html>
