<html>
<head><title>N2712 - Non-static data member initializers</title></head>
<body>
<table border=0>
<tr>
  <td><b>Doc No:</b></td>
  <td>N2712 = 08-0222</td>
</tr>
<tr>
  <td><b>Date:</b></td>
  <td>2008-08-04</td>
</tr>
<tr>
  <td><b>Reply to:</b>&nbsp;</td>
  <td>Bill Seymour &lt;stdbill.h@pobox.com&gt;</td>
</tr>
</table>

<center>

<h1>Non-static data member initializers</h1>
<h3>Michael Spertus<br/>Bill Seymour</h3>
</center>

<h2>Abstract</h2>

We propose allowing the use of initializers for non-static class and
struct data members. The purpose of this is to increase maintainability,
reduce the risk of subtle errors in complex program code, and to make the
use of initializers more consistent.

<p><hr size=5>

<h2>Acknowledgement</h2>

The authors would like to thank Jens Maurer for his many excellent
suggestions regarding the words for the Standard.  Thanks also to
Bjarne Stroustrup for several excellent suggestions making reference
to <tt><b>{}</b></tt> initializers in the rationale portion of this paper.
If any problems remain, this paper&rsquo;s authors are at fault.

<p><hr size=5>

<h2>The proposal</h2>

The basic idea is to allow non-static data members of class types to be
initialized where declared. The goal is that all of the same initialization
syntaxes may be used as for initialization of local variables; and other analyses and suggestions for
improving initialization of local variables as in
<a name="initdocs">
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/N1493.pdf">N1493</a>,
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/N1509.pdf">N1509</a>,
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/N1584.pdf">N1584</a>,
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/N1701.pdf">N1701</a>,
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/N1806.html">N1806</a>,
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/N1824.htm">N1824</a>, and
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/N1919.pdf">N1919</a>
</a>
may also be applied <i>mutatis mutandis</i> to non-static <tt>class</tt> data members.
This goal will not be reached completely, however, because to avoid parsing problems,
we no longer propose to allow initializers of the
<nobr>&ldquo;<tt><b>(</b></tt> <i>expression-list</i> <tt><b>)</b></tt>&rdquo;</nobr>
form <a href="#konaissue">as explained below</a>.<!--  On the other hand, there now
seems to be a consensus on the use of <tt><b>{}</b></tt> for initializers
(<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2575.pdf">N2575</a>),
so we use that form for some examples that used parentheses in earlier
versions of this paper.  Initializers of that form
remain in the examples immediately below, however, to preserve some history.)-->

<p>As a simple example,
<pre>
    class A {
    public:
        int a = 7;
    };
</pre>
would be equivalent to
<pre>
    class A {
    public:
        A() : a(7) {}
    };
</pre>
The real benefits of member initializers do not become apparent until a class
has multiple constructors. For many data members, especially private ones, all
constructors initialize a data member to a common value as in the next example:
<pre>
    class A {
    public:
        A(): a(7), b(5), hash_algorithm("MD5"), s("class A example") {}
        A(int a_val) : a(a_val), b(5), hash_algorithm("MD5"), s("Constructor run") {}
        A(int b_val) : a(7), b(b_val), hash_algorithm("MD5"), s("Constructor run") {}
        A(D d) : a(f(d)), b(g(d)), hash_algorithm("MD5"), s("Constructor run") {}
        int a, b;
    private:
        // Cryptographic hash to be applied to all A instances
        HashingFunction hash_algorithm;
        // String indicating state in object lifecycle
        std::string s;
    };
</pre>
Even in this simple example, the redundant code is already problematic if the
constructor arguments for <tt>hash_algorithm</tt> are copied incorrectly in one of
<tt>A</tt>&rsquo;s constructors or if one of the lifecycle states was accidentally misspelled as
<tt>"Constructor Run"</tt>. These kinds of errors can easily result in subtle bugs.
Such inconsistencies are readily avoided using member initializers.
<pre>
    class A {
    public:
        A(): a(7), b(5) {}
        A(int a_val) : a(a_val), b(5) {}
        A(int b_val) : a(7), b(b_val) {}
        A(D d) : a(f(d)), b(g(d)) {}
        int a, b;
    private:
        // Cryptographic hash to be applied to all A instances
        HashingFunction hash_algorithm("MD5");
        // String indicating state in object lifecycle
        std::string s("Constructor run");
    };
</pre>

Not only does this eliminate redundant code that must be manually synched, it
makes much clearer the distinctions between the different constructors.
(Indeed, in Java, where both forms of initialization are available,
the use of member initializers is invariably preferred by experienced
Java programmers in examples such as these.)

<p>Now suppose that it is decided that MD5 hashes are not collision resistent
enough and that SHA-1 hashes should be used. Without member initializers, all
the constructors need to be updated. Unfortunately, if one developer is unaware
of this change and creates a constructor that is defined in a different source
file and continues to initialize the cryptographic algorithm to MD5, a very hard
to detect bug will have been introduced. It seems better to keep the information
in one place.

<p>It may happen that a data member will usually have a particular value, but a
few specialized constructors will need to be cognizant of that value. If a
constructor initializes a particular member explicitly, the constructor initialization
overrides the member initializations as shown below:
<pre>
    class A {
    public:
        A(): a(7), b(5) {}
        A(int a_val) : a(a_val), b(5) {}
        A(int b_val) : a(7), b(b_val) {}
        A(D d) : a(f(d)), b(g(d)) {}
        // Copy constructor
        A(const A& aa) : a(aa.a),
                         b(aa.b),
                         hash_algorithm(aa.hash_algorithm.getName()),
                         s(aa.s) {}
        int a, b;
    private:
        // Cryptographic hash to be applied to all A instances
        HashingFunction hash_algorithm("MD5");
        // String indicating state in object lifecycle
        std::string s("Constructor run");
    };
</pre>
A few additional points are worth noting.
<ul>
<li>By allowing non-static data members of classes to be initialized in the same
    way as non-static local variables (which should be thought of as non-static
    data members of the function frame), C++ initialization becomes more
    consistent. As many of the <a href="#initdocs">documents mentioned above</a>
    point out, this is much needed.
<p><li>Because these initializers must be given in the class definition, which
    may be included in many files, it is possible that the initializers may vary
    in value depending on context. Although this is troublesome, such ODR
    problems already exist for default arguments, inline methods, member
    types, etc.; and member initializers do not appreciably aggravate them.
<p><li>There is some overlap between this proposal and constructor delegation and forwarding
    (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/N1445.htm">N1445</a>,
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/N1581.pdf">N1581</a>,
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/N1618.pdf">N1618</a>, and
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/N1898.pdf">N1898</a>).
    However, it is easy to see that neither technique obviates the other. For example,
    overriding member initializers appears difficult to do in generality through
    constructor forwarding.  (And note that Java has both member initialization and
    constructor forwarding.  This is not regarded as confusing, and most experienced
    Java programmers make regular use of both techniques based on applicability.)
<p><li>Member initializers make possible the use of copy-initialization for class
    data members. It seems likely this flexibility will prove useful just as in the
    case of local variables.
<p><li>It is intended that this proposal also supports initializer lists
    (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2575.pdf">N2575</a>)
    if they are adopted into C++0X.
</ul>

<p><a name="konaissue"><hr size=3></a>

<h3>An issue raised in Kona regarding scope of identifiers:</h3>

<p>During discussion in the Core Working Group at the September &rsquo;07 meeting in Kona,
a question arose about the scope of identifiers in the initializer.  Do we want to allow
class scope with the possibility of forward lookup; or do we want to require that the initializers
be well-defined at the point that they&rsquo;re parsed?

<h4>What&rsquo;s desired:</h4>

The motivation for class-scope lookup is that we&rsquo;d like to be able to put
anything in a non-static data member&rsquo;s initializer that we could put
in a <i>mem-initializer</i> without significantly changing the semantics
(modulo direct initialization vs. copy initialization):
<pre>
    int x();

    struct S {
        int i;
        S() : i(x()) {} // currently well-formed, uses S::x()
        // ...
        static int x();
    };

    struct T {
        int i = x(); // should use T::x(), ::x() would be a surprise
        // ...
        static int x();
    };
</pre>

<h4>Problem 1:</h4>

Unfortunately, this makes initializers of the
<nobr>&ldquo;<tt><b>(</b></tt> <i>expression-list</i> <tt><b>)</b></tt>&rdquo;</nobr>
form ambiguous at the time that the declaration is being parsed:
<pre>
    struct S {
        int i(x); // data member with initializer
        // ...
        static int x;
    };

    struct T {
        int i(x); // member function declaration
        // ...
        typedef int x;
    };
</pre>

One possible solution is to rely on the existing rule that, if a declaration
could be an object or a function, then it&rsquo;s a function:
<pre>
    struct S {
        int i(j); // ill-formed...parsed as a member function,
                  // type j looked up but not found
        // ...
        static int j;
    };
</pre>

A similar solution would be to apply another existing rule,
currently used only in templates, that if <tt>T</tt> could
be a type or something else, then it&rsquo;s something else;
and we can use &ldquo;<tt>typename</tt>&rdquo; if we really
mean a type:
<pre>
    struct S {
        int i(x); // unabmiguously a data member
        int j(typename y); // unabmiguously a member function
    };
</pre>

Both of those solutions introduce subtleties that are likely
to be misunderstood by many users (as evidenced by the many
questions on comp.lang.c++ about why
<nobr>&ldquo;<tt>int</tt> <tt>i();</tt>&rdquo;</nobr>
at block scope doesn&rsquo;t declare a default-initialized <tt>int</tt>).

<p>The solution proposed in this paper is to allow only initializers of the
&ldquo;<tt><b>=</b></tt>&nbsp;<i>initializer-clause</i>&rdquo;
and &ldquo;<b>{</b>&nbsp;<i>initializer-list</i>&nbsp;<b>}</b>&rdquo; forms.
That solves the ambiguity problem in most cases, for example:
<pre>
    HashingFunction hash_algorithm{"MD5"};
</pre>
Here, we could not use the <tt><b>=</b></tt> form because HasningFunction&rsquo;s
constructor is <tt>explicit</tt>.

<p>In especially tricky cases, a type might have to be mentioned twice.  Consider:
<pre>
    vector&lt;int&gt; x = 3; // error:  the constructor taking an int is explicit
    vector&lt;int&gt; x(3);  // three elements default-initialized
    vector&lt;int&gt; x{3};  // one element with the value 3
</pre>
In that case, we have to chose between the two alternatives by using the
appropriate notation:
<pre>
    vector&lt;int&gt; x = vector&lt;int&gt;(3); // rather than vector&lt;int&gt; x(3);
    vector&lt;int&gt; x{3}; // one element with the value 3
</pre>

<h4>Problem 2:</h4>

Another issue is that, because we propose no change to the rules for initializing
static data members, adding the <tt>static</tt> keyword could make a well-formed
initializer ill-formed:
<pre>
    struct S {
               const int i = f(); // well-formed with forward lookup
        static const int j = f(); // always ill-formed for statics
        // ...
        constexpr static int f() { return 0; }
    };
</pre>

<h4>Problem 3:</h4>

A third issue is that class-scope lookup could turn a compile-time error
into a run-time error:
<pre>
    struct S {
        int i = j; // ill-formed without forward lookup, undefined behavior with
        int j = 3;
    };
</pre>
(Unless caught by the compiler, <tt>i</tt> might be intialized
with the undefined value of <tt>j</tt>.)

<h4>The proposal:</h4>

CWG had a 6-to-3 straw poll in Kona in favor of class-scope lookup;
and that is what this paper proposes, with initializers
for non-static data members limited to the
<nobr>&ldquo;<tt><b>=</b></tt> <i>initializer-clause</i>&rdquo;</nobr>
and &ldquo;<b>{</b>&nbsp;<i>initializer-list</i>&nbsp;<b>}</b>&rdquo; forms.

<p>We believe:
<blockquote>
<b>Problem 1:</b>  This problem does not occur as we don&rsquo;t propose the
<tt><b>()</b></tt> notation.  The <tt><b>=</b></tt> and <tt><b>{}</b></tt>
initializer notations do not suffer from this problem.
<p><b>Problem 2:</b>  adding the <tt>static</tt> keyword makes a number
of differences, this being the least of them.
<p><b>Problem 3:</b>  this is not a new problem, but is the same
order-of-initialization problem that
already exists with constructor initializers.
</blockquote>

<p><a name="autoreasons"><hr size=3></a>

<h3>A recent issue regarding <tt>auto</tt>:</h3>

One national body dislikes allowing the <tt>auto</tt>
<nobr><i>type-specifier</i></nobr> for
<nobr>non-<tt>static</tt>s.</nobr>
From an e-mail to the authors:

<blockquote>
<blockquote>
<pre>
template&lt; class T &gt;
struct MyType : T {
  auto data = func();
  static const size_t erm = sizeof(data);
};
</pre>
</blockquote>

In order to determine the layout of X, we now have 2-phase name lookup and ADL.
Note that func could be either a type or a function; it may be found
in T,
the namespace of MyType, the associated namespace(s) of T when instantiated,
the global namespace, an anonymous namespace, or any namespaces subject to
a using directive.  With care we could probably throw some concept_map lookup
in for luck.

<p>Depending on the order of header inclusion I might even get different results
for ADL, and break the One Definition Rule - which is not required to be diagnosed.
</blockquote>

Because of this controversy, the authors no longer propose that <tt>auto</tt>
be allowed for non-<tt>static</tt> data members.

<h4>Late-breaking news:</h4>

A post on <i>comp.lang.c++.moderated</i> pointed out that one can do the
same thing with <tt>decltype</tt> anyway, so allowing non-<tt>static</tt> DMs
to be declared <tt>auto</tt> is once again proposed, but in
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2713">N2713</a>,
not in this paper.

<p><hr size=3>

<h3>
  Incorporation of initializer lists:
</h3>

<p>There are seven changes in suggested standardese to get
from D2628, which CWG considered on Thursday in Sofia-Antipolis,
to the immediately previous version of this paper,
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2673">N2673</a>:
<ul>
<li>From CWG minutes on the wiki (not related to initializer lists):
<ul>
<li>3.3.6 [basic.scope.class] &ndash; change
    &ldquo;initializer&rdquo; to &ldquo;<i>assignment-initializer</i>&rdquo;
<li>global &ndash; change &ldquo;<i>assignment-initializer</i>&rdquo; to &ldquo;<i>equal-initializer</i>&rdquo;
<li>3.4.1 [basic.lookup.unqual] &ndash; add member initializers to p8
</ul>
<li>Not yet considered by CWG (incorporating initializer lists):
<ul>
<li>8.5 [dcl.init] &ndash; add <i>braced-init-list</i> to <i>initializer</i> grammar
<li>global &ndash; change &ldquo;<i>equal-initializer</i>&rdquo; to &ldquo;<i>brace-or-equal-initializer</i>&rdquo;
<li>8.5 [dcl.init] &ndash; changes to 8.5p12-13 removed from this paper
    because words in N2672 suffice
<li>8.5.4 [dcl.init.list] &ndash; add a bullet in the note that lists
    the places where initializer lists can be used
</ul>
</ul>

And triggered by Jens Maurer&rsquo;s review of this paper, we note that
initializer lists are still not allowed on static data members.
Although static DMs are not addressed herein, if initializer
lists should be allowed on statics before this paper gets
voted in, our suggestions for 9.4.2 might have to change as well.

<p>To get from <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2673">N2673</a>
to this paper, there are six changes to the suggested standardese, all of which we believe
to be editorial:
<ul>
<li>8.5.4 &ndash; removed, e.g., [dcl.init] from the references (not in the WP)
<li>9.2p4 &ndash; removed the word &ldquo;literal&rdquo; from the text to be deleted
    (doesn&rsquo;t appear in the current WP)
<li>12.1 &ndash; removed from this paper some text that <i>doesn&rsquo;t</i> change
    to make the change more obvious
<li>12.7 &ndash; corrected one typo and two omissions from N2673 (text that
    <i>doesn&rsquo;t</i> change didn&rsquo;t agree with the WP)
</ul>

<p><hr size=5>

<h2>
  Suggested changes to the Working Paper,
  <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2691">N2691</a>
</h2>

<h4>3.3.6 Class Scope [basic.scope.class]</h4>

Add to 3.3.6p1 1):

<blockquote>
The potential scope of a name declared in a class consists not only
of the declarative region following the name&rsquo;s point of declaration,
but also of all function bodies<ins>, <i>brace-or-equal-initializers</i>
of non-static data members,</ins>
and default arguments in that class (including such things in nested classes).
</blockquote>

<p><hr size=3>

<h4>3.4.1 Unqualified name lookup [basic.lookup.unqual]</h4>

Add to 3.4.1p8:

<blockquote>
A name used in the definition of a member function (9.3) of class X
following the function&rsquo;s <i>declarator-id</i> <sup>28)</sup><ins>,
or in the <i>brace-or-equal-initializer</i> of a non-static data member
(9.2) of class X,</ins> shall be declared in one of the following ways:
</blockquote>

<p><hr size=3>

<h4>5.1 Primary expressions [expr.prim]</h4>

Change 5.1p3:

<blockquote>
The keyword <tt>this</tt> names a pointer to the object for which a non-static member
function (9.3.2) is invoked <ins>or a non-static data member&rsquo;s initializer (9.2)
is evaluated</ins>.
The keyword <tt>this</tt> shall be used only inside
a non-static class member function body (9.3) <ins>or in an
<nobr><i>brace-or-equal-initializer</i></nobr> for
a non-static data member (9.2)</ins>.  The type of the expression is a pointer
to the function&rsquo;s <ins>or non-static data member&rsquo;s</ins> class <del>(9.3.2)</del>,
possibly with <nobr>cv-qualifiers</nobr> on the class type.  The expression is an rvalue.
</blockquote>

<p><hr>

Add a bullet to 5.1p11:

<blockquote>
An <i>id-expression</i> that denotes a non-static data member or
non-static member function of a class can only be used:
<blockquote>
&mdash; as part of a class member access (5.2.5) in which the
object-expression refers to the member&rsquo;s class or a class
derived from that class, or
<p>&mdash; to form a pointer to member (5.3.1), or
<p>&mdash; in the body of a non-static member function of that class
or of a class derived from that class (9.3.1), or
<p>&mdash; in a <i>mem-initializer</i> for a constructor for that class or
for a class derived from that class (12.6.2), or
<p><ins>&mdash; in a <nobr><i>brace-or-equal-initializer</i></nobr>
for a non-static data member of that class or
of a class derived from that class (12.6.2), or</ins>
<p>&mdash; if that <i>id-expression</i> denotes a non-static data member
and it is the sole constituent of an unevaluated operand,
except for optional enclosing parentheses. [ Example:
<br>...
</blockquote>
</blockquote>

<p><a name="autochange"><hr size=3></a>

<h4>7.1.6.4 <tt>auto</tt> specifier [dcl.spec.auto]</h4>

<p>Change paragraph 4:
<blockquote>
The <tt>auto</tt> <i>type-specifier</i> can also be used in declaring an object
in the <i>condition</i> of a selection statement (6.4) or an iteration statement (6.5),
in the <i>type-specifier-seq</i> in a <i>new-type-id</i> (5.3.4), and in declaring
a static data member with
<del>a <nobr><i>constant-initializer</i></nobr></del>
<ins>a <nobr><i>brace-or-equal-initializer</i></nobr></ins>
that appears within the <nobr><i>member-specification</i></nobr> of a class definition (9.4.2).
</blockquote>

<p><hr size=3>

<h4>8.5 Initializers [dcl.init]</h4>


Change the grammar for initializer:

<blockquote>

<i>initializer:</i><br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;</tt><del><b>=</b>&nbsp;&nbsp;<i>initializer-clause</i></del>&nbsp;&nbsp;<ins><i>brace-or-equal-initializer</i></ins><br>

<tt>&nbsp;&nbsp;&nbsp;&nbsp;</tt><tt><b>(</b></tt>&nbsp;&nbsp;<i>expression-list</i>&nbsp;&nbsp;<tt><b>)</b></tt><br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;</tt><del><i>braced-init-list</i></del>

<p><ins><i>brace-or-equal-initializer:</i></ins><br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;</tt><ins><tt><b>=</b></tt>&nbsp;&nbsp;<i>initializer-clause</i></ins><br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;</tt><ins><i>braced-init-list</i></ins>
</blockquote>
<!--
<p><hr>

Add to 8.5p12:

<blockquote>
The initialization that occurs in argument passing, function return, throwing an exception (15.1),
handling an exception (15.3), <ins>initializing a non-static data member with
a <nobr><i>brace-or-equal-initializer</i>,</nobr></ins>
and <nobr>brace-enclosed</nobr> initializer lists (8.5.1)
is called <nobr><i>copy-initialization</i></nobr> and is equivalent to the form
<blockquote>
<tt>T x = a;</tt>
</blockquote>
</blockquote>

<p><hr>

Change &ldquo;base and member initializers&rdquo; to &ldquo;<i>mem-initializers</i>&rdquo; in 8.5p13:

<blockquote>
The initialization that occurs in <tt>new</tt> expressions (5.3.4),
<tt>static_cast</tt> expressions (5.2.9), functional notation type conversions (5.2.3),
and <del>base and member initializers</del> <ins><i>mem-initializers</i></ins> (12.6.2)
is called <i>direct-initialization</i> and is equivalent to the form
<blockquote>
<tt>T x(a);</tt>
</blockquote>
</blockquote>

-->

<p><hr size=3>
<h4>8.5.4 List-initialization [dcl.init.list]</h4>

Add a bullet to the note:

<blockquote>
<ul>
<li>as the initializer in a variable definition (8.5)
<li>as the initializer in a new expression (5.3.4)
<li>in a return statement (6.6.3)
<li>as a function argument (5.2.2)
<li>as a subscript (5.2.1)
<li>as an argument to a constructor invocation (8.5, 5.2.3)
<ins><li>as an initializer for a non-static data member (9.2)</ins>
<li>as a base-or-member initializer (12.6.2)
<li>on the right-hand side of an assignment (5.17)
</ul>
</blockquote>

<p><hr size=3>
<h4>9.2 Class members [class.mem]</h4>

Change <i>constant-initializer</i> to <i>brace-or-equal-initializer</i> in the second line of <i>member-declarator</i>:

<blockquote>
<i>member-declarator:</i>
<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;</tt><i>declarator&nbsp;&nbsp;pure-specifier<small><sub>opt</sub></small></i>
<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;</tt><i>declarator&nbsp;&nbsp;<del>constant-initializer</del> <ins>brace-or-equal-initializer</ins><small><sub>opt</sub></small></i>
<br><tt>&nbsp;&nbsp;&nbsp;&nbsp;</tt><i>identifier<small><sub>opt</sub></small></i>&nbsp;&nbsp;<tt>:</tt>&nbsp;&nbsp;<i>constant-expression</i>
</blockquote>

<p><hr>

Delete the final rule entirely:
<blockquote>
<del><i>constant-initializer</i>:</del><br><tt>&nbsp;&nbsp;&nbsp;&nbsp;</tt><del>= <i>constant-expression</i></del>
</blockquote>

<p><hr>

Add to 9.2p2:

<blockquote>
A class is considered a completely-defined object type (3.9) (or complete type) at the closing
<b><tt>}</tt></b> of the <nobr><i>class-specifier</i>.</nobr>
Within the class <nobr><i>member-specification</i>,</nobr>
the class is regarded as complete within function bodies, default arguments,
<nobr><i>exception-specification</i>s<ins>,</ins></nobr><ins> and
<nobr><i>brace-or-equal-initializer</i>s</nobr> for non-static data members</ins>
(including such things in nested classes).
Otherwise it is regarded as incomplete within its own
class <nobr><i>member-specification</i>.</nobr>
</blockquote>

<p><hr>

Delete 9.2p4 entirely:
<blockquote>
<del>A <i>member-declarator</i> can contain a <i>constant-initializer</i> only if it declares
a <tt>static</tt> member (9.4) of <tt>const</tt> type, see 9.4.2.</del>
</blockquote>

<p><hr size=3>

Add a new paragraph after the new 9.2p4 (which was p5 before the deletion
immediately above):

<blockquote>
<ins>A member can be initialized using a <nobr><i>brace-or-equal-initializer</i>.</nobr>
(For static data members, see 9.4.2 [class.static.data]; for non-static
data members, see 12.6.2 [class.base.init]).</ins>
<!--<ins>A non-static data member with a <nobr><i>brace-or-equal-initializer</i></nobr> will be
initialized by the constructor.</ins>-->
</blockquote>

<p><hr size=3>

<h4>9.4.2 Static data members [class.static.data]</h4>

Change 9.4.2p3:

<!--
<blockquote>
If a <tt>static</tt> data member is of <tt>const</tt> literal type,
its declaration in the class definition can specify
<del>a <i>constant-initializer</i>.
A <tt>static</tt> data member of literal type can be declared
in the class definition with the <tt>constexpr</tt> specifier;
if so, its declaration shall specify a <i>constant-initializer</i>.
In both these cases, the member may appear in integral constant
expressions.</del>
The member shall still be defined in a namespace scope
if it is used in the program and the namespace scope definition
shall not contain an <i>initializer</i>.
</blockquote>
-->
<blockquote>
If a <tt>static</tt> data member is of <tt>const</tt> literal type,
its declaration in the class definition can specify
<del>a <i>constant-initializer</i></del> <ins>a <i>brace-or-equal-initializer</i>
with an <i>initializer-clause</i> that is an integral constant expression</ins>.
A <tt>static</tt> data member of literal type can be declared
in the class definition with the <tt>constexpr</tt> specifier;
if so, its declaration shall specify <del>a <i>constant-initializer</i></del>
<ins>a <i>brace-or-equal-initializer</i>
with an <i>initializer-clause</i> that is an integral constant expression</ins>.
In both these cases, the member may appear in integral constant
expressions. The member shall still be defined in a namespace scope
if it is used in the program and the namespace scope definition
shall not contain an <i>initializer</i>.
</blockquote>
<!--
<blockquote>
<del>If a static data member is of <tt>const</tt> literal type,
its declaration in the class definition
can specify a <nobr><i>constant-initializer</i>.</nobr></del>
<ins>A declaration of a <tt>static</tt> data member in a class definition
may only specify a <nobr><i>brace-or-equal-initializer</i></nobr>
if that data member is of <tt>const</tt> literal type, in which case
the <nobr><i>initializer-clause</i></nobr> shall be an integral constant
expression (5.19).</ins>
A <tt>static</tt> data member of literal type can be declared in the class definition
with the <tt>constexpr</tt> specifier; if so, its declaration shall specify
<del>a <nobr><i>constant-initializer</i></nobr></del> <ins>a <nobr><i>brace-or-equal-initializer</i></nobr>
with an <nobr><i>initializer-clause</i></nobr> that is an integral constant expression (5.19)</ins>.
<del>In both these cases, the member</del>
<ins>A <tt>static</tt> data member that is of <tt>const</tt> literal type,
or that is declared with the <tt>constexpr</tt> specifier,</ins>
may appear in integral constant expressions.
The member shall still be defined in a namespace scope if it is used in the program<ins>;</ins>
and <ins>if the <nobr><i>member-declarator</i></nobr> contains an
<nobr><i>brace-or-equal-initializer</i></nobr>,</ins> the namespace scope definition
shall not contain an <i>initializer</i>.
</blockquote>
-->

<p><hr size=3>

<h4>12.1 Constructors [class.ctor]</h4>

Add a new bullet between the first and second in 12.1p5:

<blockquote>
A <i>default</i> constructor for a class X is a constructor of class X
that can be called without an argument. &hellip;
<!--without an argument. If there is no user-declared constructor for class X,
a default constructor is implicitly declared.  An implicitly-declared default constructor is
an <tt>inline</tt> <tt>public</tt> member of its class. A default constructor is <i>trivial</i>
if it is not user-provided (8.4) and if:-->
<blockquote>
<p>&mdash; its class has no virtual functions (10.3) and no virtual base classes (10.1), and
<p><ins>&mdash; no non-static data member of its class has a <nobr><i>brace-or-equal-initializer</i>,</nobr>
and</ins> <p>&mdash; all the direct base classes of its class have trivial default constructors, and
<p>&mdash; for all the non-static data members of its class that are of class type
(or array thereof), each such class has a trivial default constructor.
</blockquote>
</blockquote>

<p><hr size=3>

<h4>12.6.2 Initializing bases and members [class.base.init]</h4>

<p>Add a new first bullet to 12.6.2p4:

<blockquote>
If a given non-static data member or base class is not named by a
<nobr><i>mem-initializer-id</i></nobr>
(including the case where there is no
<nobr><i>mem-initializer-list</i></nobr> because the constructor
has no <nobr><i>ctor-initializer</i>),</nobr></ins> then
<blockquote>
<!--
<ins>&mdash; If the entity is a non-static data member
that has a <nobr><i>brace-or-equal-initializer</i>,</nobr>
the entity is copy-initialized with the value of the
<nobr><i>initializer-clause</i>.</nobr></ins>
-->
<ins>&mdash; If the entity is a non-static data member
that has a <nobr><i>brace-or-equal-initializer</i>,</nobr>
the entity is initialized as specified in 8.5.</ins>
<p>
&mdash; <del>If</del> <ins>Otherwise, if</ins> the entity is a non-static ...
</blockquote>
</blockquote>

<p><hr>

Change the part of 12.6.2p4 after the bullets and add an example:

<blockquote>
After the call to a constructor for class X has completed,
if a member of X is neither
<!-- specified in the constructor&rsquo;s
<i>mem-initializers</i>, <ins>nor copy-initialized,</ins> nor default-initialized,
nor value-initialized,-->
<del>specified in the constructor&rsquo;s <i>mem-initializers</i>,
nor default-initialized, nor value-initialized,</del>
<ins>initialized</ins>
nor given a value during execution of the <i>compound-statement</i>
of the body of the constructor, the member has indeterminate value.
<p><ins>[ <i>Example:</i></ins>
<pre>
<ins>struct A {</ins>
    <ins>A();</ins>
<ins>};</ins>

<ins>struct B {</ins>
    <ins>B(int);</ins>
<ins>};</ins>

<ins>struct C {</ins>
    <ins>C() { }   // initializes members as follows:</ins>
    <ins>A a;        // ok: calls A::A()</ins>
    <ins>const B b;  // error: B has no default constructor</ins>
    <ins>int i;      // ok: "i" has indeterminate value</ins>
    <ins>int j = 5;  // ok: "j" has the value "5"</ins>
<ins>};</ins>
</pre>
<p><ins>&mdash; <i>end example</i> ]</ins>
</blockquote>

<p><hr>

Add a new paragraph 5 and an example after 12.6.2p4:
<blockquote>
<ins>If a given non-static data member has both a <nobr><i>brace-or-equal-initializer</i></nobr>
and a <nobr><i>mem-initializer</i>,</nobr>
the initialization specified by the <nobr><i>mem-initializer</i></nobr> is performed,
and the non-static data member&rsquo;s <nobr><i>brace-or-equal-initializer</i></nobr> is ignored.
<p>[ <i>Example:</i> given</ins>
<pre>
<ins>struct A {</ins>
    <ins>int i = /* some integer expression with side effects */ ;</ins>
    <ins>A(int arg) : i(arg) { }</ins>
    <ins>// ...</ins>
<ins>};</ins>
</pre>
<ins>the <tt>A(int)</tt> constructor will simply initialize <tt>i</tt> to the value
of <tt>arg</tt>, and the side effects in <tt>i</tt>&rsquo;s
<nobr><i>brace-or-equal-initializer</i></nobr>
will not take place. &mdash; <i>end example</i> ]</ins>
</blockquote>

<p><hr size=3>

<h4>12.7 Construction and destruction [class.cdtor]</h4>

Add a new paragraph before 12.7p4 and rewrite the existing
12.7p4, 5 &amp; 6 to use the new <i>construction-destruction
operation</i> term:

<blockquote>
<ins>
Constructors (including <nobr><i>mem-initializer</i>s</nobr> for data members),
<nobr><i>brace-or-equal-initializer</i>s</nobr> for non-static data members, and
destructors are called <i>construction-destruction operations</i>.
</ins>

<p>Member functions, including virtual functions (10.3), can be called
during construction or destruction (12.6.2). When a virtual function
is called directly or indirectly from a <del>constructor (including from
the <i>mem-initializer</i> for a data member) or from a destructor,</del>
<ins>construction-destruction operation</ins> and the object to which the call
applies is the object under construction or destruction, the function
called is the one defined in the <del>constructor or destructor&rsquo;s</del>
<ins>construction-destruction operation&rsquo;s</ins>
own class or in one of its bases, but not a function overriding
it in a class derived from the <del>constructor or destructor&rsquo;s</del>
<ins>construction-destruction operation&rsquo;s</ins> class,
or overriding it in one of the other base classes of the most derived object (1.8).
If the virtual function call uses an explicit class member access (5.2.5)
and the object-expression refers to the object under construction or destruction
but its type is neither the <del>constructor or destructor&rsquo;s</del>
<ins>construction-destruction operation&rsquo;s</ins> own class or
one of its bases, the result of the call is undefined. [ Example:  &hellip;
</blockquote>
[no change to example]
<blockquote>
<p>The <tt>typeid</tt> operator (5.2.8) can be used during construction or destruction (12.6.2).
When <tt>typeid</tt> is used in a <del>constructor (including from the <i>mem-initializer</i>
for a data member) or in a destructor,</del> <ins>construction-destruction operation</ins>
or used in a function called (directly or indirectly) from a <del>constructor or destructor</del>
<ins>construction-destruction operation</ins>, if the operand of <tt>typeid</tt> refers to
the object under construction or destruction, <tt>typeid</tt> yields the <tt>std::type_info</tt>
object representing the <del>constructor or destructor&rsquo;s</del>
<ins>construction-destruction operation&rsquo;s</ins> class. If the operand of
<tt>typeid</tt> refers to the object under construction or destruction and the
static type of the operand is neither the <del>constructor or destructor&rsquo;s</del>
<ins>construction-destruction operation&rsquo;s</ins> class nor one of its bases,
the result of <tt>typeid</tt> is undefined.

<p><tt>Dynamic_casts</tt> (5.2.7) can be used during construction or destruction (12.6.2).
When a <tt>dynamic_cast</tt> is used in a <del>constructor (including from the
<i>mem-initializer</i> for a data member) or in a destructor</del>
<ins>construction-destruction operation</ins>, or used in a function called
(directly or indirectly) from a <del>constructor or destructor</del>
<ins>construction-destruction operation</ins>,
if the operand of the <tt>dynamic_cast</tt> refers to the object under
construction or destruction, this object is considered to be a most derived
object that has the type of the <del>constructor or destructor&rsquo;s</del>
<ins>construction-destruction operation&rsquo;s</ins> class. If the operand
of the <tt>dynamic_cast</tt> refers to the object under construction or destruction
and the static type of the operand is not a pointer to or object of the
<del>constructor or destructor&rsquo;s</del>
<ins>construction-destruction operation&rsquo;s</ins> own class or one of its bases,
the <tt>dynamic_cast</tt> results in undefined behavior.

</blockquote>

<!--

<p><hr size=3>

<h4>12.7 Construction and destruction [class.cdtor]</h4>

Include <i>brace-or-equal-initializer</i>s in the second sentence of 12.7p4:

<blockquote>
Member functions, including virtual functions (10.3), can be called
during construction or destruction (12.6.2). When a
virtual function is called directly or indirectly from a constructor
(including from the
<nobr><i>mem-initializer</i></nobr> for a data member)<ins>,
from the <nobr><i>brace-or-equal-initializer</i></nobr> for
a non-static data member,</ins>
or from a destructor, and the object to which the call
applies is the object under construction or destruction, the function
called is the one defined in the constructor or destructor&rsquo;s own class
or in one of its bases, but not a function overriding it in a class derived
from the constructor or destructor&rsquo;s class, or overriding it in one of
the other base classes of the most derived object (1.8). If the virtual
function call uses an explicit class member access (5.2.5) and the
object-expression refers to the object under construction or destruction
but its type is neither the constructor or destructor&rsquo;s own class or
one of its bases, the result of the call is undefined. [ Example:
<br>...
</blockquote>

<p><hr>

<p>A similar change appears twice in 12.7p5:
<blockquote>
The <tt>typeid</tt> operator (5.2.8) can be used during construction
or destruction (12.6.2). When <tt>typeid</tt> is used in a constructor
(including <del>from</del> <ins>in</ins> the
<nobr><i>mem-initializer</i></nobr> for a data member)<ins>,
in the <nobr><i>brace-or-equal-initializer</i></nobr> for
a non-static data member,</ins> or in a destructor,
or used in a function called (directly or indirectly)
from a constructor<ins>, from the
<nobr><i>brace-or-equal-initializer</i></nobr> for
a non-static data member,</ins> or from a destructor,
if the operand
of <tt>typeid</tt> refers to the object under construction or destruction,
<tt>typeid</tt> yields the <tt>std::type_info</tt> object representing
the constructor or destructor&rsquo;s class. If the operand of <tt>typeid</tt>
refers to the object under construction or destruction and the static type
of the operand is neither the constructor or destructor&rsquo;s class
nor one of its bases, the result of <tt>typeid</tt> is undefined.
</blockquote>

<p><hr>

<p>And twice in 12.7p6:
<blockquote>
<tt>Dynamic_cast</tt>s (5.2.7) can be used during construction or destruction (12.6.2).
When a <tt>dynamic_cast</tt> is used in a constructor
(including <del>from</del> <ins>in</ins> the
<nobr><i>mem-initializer</i></nobr> for a data member)<ins>,
in the <nobr><i>brace-or-equal-initializer</i></nobr> for
a non-static data member,</ins> or in a destructor,
or used in a function called (directly or indirectly)
from a constructor<ins>, from the
<nobr><i>brace-or-equal-initializer</i></nobr> for
a non-static data member,</ins> or from a destructor,
if the operand of the <tt>dynamic_cast</tt>
refers to the object under construction or destruction, this object is considered
to be a most derived object that has the type of the constructor or destructor&rsquo;s
class. If the operand of the <tt>dynamic_cast</tt> refers to the object under
construction or destruction and the static type of the operand is not a pointer
to or object of the constructor or destructor&rsquo;s own class or one of its bases,
the <tt>dynamic_cast</tt> results in undefined behavior.
</blockquote>

-->

<p><hr size=3>

<h4>12.8 Copying class objects [class.copy]</h4>

Add a note after the first sentence of 12.8p8:
<blockquote>
The implicitly-defined or explicitly-defaulted copy constructor for class X performs
a memberwise copy of its subobjects. <ins>[ <i>Note:</i>
<nobr><i>brace-or-equal-initializers</i></nobr> of non-static data members are ignored.
See also the example in 12.6.2. &mdash; <i>end note</i> ]</ins>
The order of copying is the same as the order of initialization of bases and members
in a user-defined constructor (see 12.6.2). Each subobject is copied in the manner
appropriate to its type:
</blockquote>

<p><hr size=5>
</body>
</html>
