<html>
<head>
<title>Extending sizeof to apply to non-static data members without an object</title>
</head>

<body>
Doc. no.: N2150=07-0010<br/>
Date: 2007-01-07<br/>
Project: Programming Language C++<br/>
Reply-to: Jens Maurer &lt;Jens.Maurer@gmx.net&gt;<br/>


<h1>Extending sizeof to apply to non-static data members without an object</h1>


<h2>1 Introduction</h2>

Given some class C with a data member m,
<blockquote>
<pre>
struct C {
   some_type m;
   // ...
};
</pre>
</blockquote>

the current standard makes it ill-formed to refer to <code>m</code> in
<code>sizeof</code> expressions without providing an object.  For
example, uses such as <code>sizeof(C::m)</code> (outside of
<code>C</code>) or <code>sizeof(m)</code> (in a static member of
<code>C</code>) are ill-formed.
<p>
That issue was discussed while considering core issue 198, but it was
resolved to clarify the wording, but continue to not allow uses such
as those outlined above.
<p>
New interest was raised with Herb Sutter's message c++std-core-11555,
which showed that some support exists to make such uses well-formed.
<p>
This paper presents specific wording changes to the Working Paper, to
which William Michael Miller and Clark Nelson contributed valuable
comments.


<h2>2 Problem Description</h2>

Given some class C with a data member m,
<blockquote>
<pre>
struct C {
   some_type m;
   // ...
};
</pre>
</blockquote>

there is no way to apply <code>sizeof</code> to <code>m</code> without
having an object available for use in a class member access
expression that the <code>sizeof</code> operator could be apply to.
<p>
In the definition of a static member of <code>C</code>, a seemingly
simple (but invalid) expression such as <code>sizeof(m)</code> must be
much adorned to obtain the valid expression <code>sizeof(((C*)
0)->m)</code>.  A similar transformation is required for
<code>sizeof(C::m)</code>.
<p>
This is counterintuitive and hard to teach.
<p>
<code>typeof</code> applied to an entity other than an object of
polymorphic class type has exactly the same issues, and any future
<code>alignof</code> (or similar) will raise the very same issue.


<h2>3 Proposed Solution</h2>

Make the indicated uses valid by introducing the following changes.
<p>
First, introduce the term "unevaluated expression" that applies to
operands of specific operators where the operation is evaluated at
compile-time.
<p>
Second, use that term both in the definition of the ODR and in the
list of permissible uses of names of non-static members in section
5.1p10.
<p>
Finally, remove any redundant restrictions on the same subject
throughout clause 9.


<h2>4 Proposed Changes to the Working Paper</h2>

Change the beginning of section 3.2 basic.def.odr paragraph 2 to use
the term "unevaluated expression".
<blockquote>
<strike>An expression is <em>unevaluated</em> if it is the operand of the
<code>sizeof</code> operator (5.3.3 expr.sizeof), or if it is the
operand of the <code>typeid</code> operator and it is not an lvalue of
a polymorphic class type (5.2.8 expr.typeid). All other expressions
are <em>potentially evaluated</em>.</strike> <b>An expression is
<em>potentially evaluated</em> unless it is an unevaluated expression
(clause 5 expr) or a subexpression thereof.</b>
</blockquote>

Change section 4.1 conv.lval paragraph 2 as indicated:
<blockquote>
When an lvalue-to-rvalue conversion occurs within <strike>the operand
of sizeof (5.3.3)</strike> <b>an unevaluated expression (clause 5
expr)</b> the value contained in the referenced object is not
accessed<strike>, since that operator does not evaluate its
operand</strike>. Otherwise, ...
</blockquote>

Add a new paragraph to section 5 after paragraph 8:
<blockquote>
<b>Clause 5 expr specifies for some operators that some of their
operands are <em>unevaluated expressions</em> (5.3.3 expr.sizeof,
5.2.8 expr.typeid).  An unevaluated expression is not evaluated. [
<em>Note</em>: In an unevaluated expression, a non-static class member
may be named (5.1 expr.prim) and naming of objects or functions does
not, by itself, require that a definition be provided (3.2
basic.def.odr). ]</b>
</blockquote>


In section 5.1 expr.prim paragraph 10, add a bullet:
<blockquote>
An <em>id-expression</em> that denotes a non-static data member or
non-static member function of a class can only be used:
<p>
<ul>
<li>...<b>, or</b>
<li><b>if that <em>id-expression</em>, optionally enclosed in
parentheses, is an unevaluated expression.</b>
</ul>
</blockquote>


Modify section 5.2.8 expr.typeid at the end of paragraph 3 as
indicated:
<blockquote>
<strike>The expression is not evaluated.</strike> <b>The expression is
an unevaluated expression (clause 5 expr).</b>
</blockquote>



Change section 5.3.3 expr.sizeof paragraph 1 as indicated:
<blockquote>
The <code>sizeof</code> operator yields the number of bytes in the
object representation of its operand. The operand is either an
expression, which is <strike>not evaluated</strike> <b>an unevaluated
expression (clause 5 expr)</b>, or a parenthesized <em>type-id</em>. ...
</blockquote>

Replace section 9.2 class.mem paragraph 9
<blockquote>
<strike>Each occurrence in an expression of the name of a non-static data
member or non-static member function of a class shall be expressed as
a class member access (5.2.5), except when it appears in the formation
of a pointer to member (5.3.1), when it appears in the
body of a non-static member function of its class or of a class
derived from its class (9.3.1), or when it appears in a
mem-initializer for a constructor for its class or for a class derived
from its class (12.6.2).</strike>
</blockquote>
by a note

<blockquote>
<b>[ <em>Note</em>: See 5.1 expr.prim for restrictions on the use of
non-static data members and non-static member functions. ]</b>
</blockquote>

Replace the end of section 9.4 class.static paragraph 4
<blockquote>
... <strike>The definition of a static member shall not use directly the names of
the non-static members of its class or of a base class of its class
(including as operands of the sizeof operator).  The definition of a
static member may only refer to these members to form pointer to
members (5.3.1) or with the class member access syntax (5.2.5).</strike>
</blockquote>
by a note
<blockquote>
... <b>[ <em>Note</em>: See 5.1 expr.prim for restrictions on the use of
non-static data members and non-static member functions. ]</b>
</blockquote>

Replace the note in section 9.7 class.nest paragraph 1

<blockquote>
[ <em>Note</em>: <strike>In accordance with 9.2 class.mem, except by
using explicit pointers, references, and object names, declarations in
a nested class shall not use non-static data members or
non-static member functions from the enclosing class.  This
restriction applies in all constructs including the operands of the
sizeof operator</strike>. -- <em>end note</em> ]
</blockquote>

by

<blockquote>
<b>[ <em>Note</em>: See 5.1 expr.prim for restrictions on the use of
non-static data members and non-static member functions.
 -- </em>end note</em> ]</b>
</blockquote>

Change one line of the example in section 9.7 class.nest paragraph 1 from
<blockquote>
<pre>
     int a = sizeof(x);   // error: direct use of enclose::x even in sizeof
</pre>
</blockquote>
to
<blockquote>
<pre>
     int a = sizeof(x);   // OK: operand of sizeof is an unevaluated expression
</pre>
</blockquote>


</body>
</html>
