<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<TITLE>
    CWG Issue 408</TITLE>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<STYLE TYPE="text/css">
  INS { text-decoration:none; font-weight:bold; background-color:#A0FFA0 }
  .INS { text-decoration:none; background-color:#D0FFD0 }
  DEL { text-decoration:line-through; background-color:#FFA0A0 }
  .DEL { text-decoration:line-through; background-color: #FFD0D0 }
  @media (prefers-color-scheme: dark) {
    HTML { background-color:#202020; color:#f0f0f0; }
    A { color:#5bc0ff; }
    A:visited { color:#c6a8ff; }
    A:hover, a:focus { color:#afd7ff; }
    INS { background-color:#033a16; color:#aff5b4; }
    .INS { background-color: #033a16; }
    DEL { background-color:#67060c; color:#ffdcd7; }
    .DEL { background-color:#67060c; }
  }
  SPAN.cmnt { font-family:Times; font-style:italic }
</STYLE>
</HEAD>
<BODY>
<P><EM>This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21
  Core Issues List revision 118b.
  See http://www.open-std.org/jtc1/sc22/wg21/ for the official
  list.</EM></P>
<P>2025-09-28</P>
<HR>
<A NAME="408"></A><H4>408.
  
sizeof applied to unknown-bound array static data member of template
</H4>
<B>Section: </B>13.7.2.5&#160; [<A href="https://wg21.link/temp.static">temp.static</A>]
 &#160;&#160;&#160;

 <B>Status: </B>CD2
 &#160;&#160;&#160;

 <B>Submitter: </B>Nathan Myers
 &#160;&#160;&#160;

 <B>Date: </B>14 Apr 2003<BR>


<P>[Voted into WP at March, 2010 meeting.]</P>



<P>Is this allowed?</P>
<PRE>
  template&lt;typename T&gt;
    struct X
    {
        static int s[];
        int c;
    };

  template&lt;typename T&gt;
    int X&lt;T&gt;::s[sizeof(X&lt;T&gt;)];

  int* p = X&lt;char&gt;::s;
</PRE>

<P>I have a compiler claiming that, for the purpose of sizeof(), X&lt;T&gt; is
an incomplete type, when it tries to instantiate X&lt;T&gt;::s.  It seems to
me that X&lt;char&gt; should be considered complete enough for sizeof even
though the size of s isn't known yet.</P>


<P>
<U>John Spicer:</U>
This is a problematic construct that is currently allowed but which I think
should be disallowed.</P>

<P>I tried this with a number of compilers.
None of which did the right thing.
The EDG front end accepts it, but gives X&lt;...&gt;::s the wrong size.</P>

<P>It appears that most compilers evaluate the
"declaration" part of the static
data member definition only once when the definition is processed.  The
initializer (if any) is evaluated for each instantiation.</P>

<P>This problem is solvable, and if it were
the only issue with incomplete arrays
as template static data members, then it would make
sense to solve it, but there are other problems.</P>

<P>The first problem is that the size of the static data member is
only known if a template definition of the static data member is
present.  This is weird to start with, but it also means that sizes
would not be available in general for exported templates.</P>

<P>The second problem concerns the rules for specialization.  An explicit
specialization for a template instance can be provided up until the
point that a use is made that would cause an implicit instantiation.
A reference like "sizeof(X&lt;char&gt;::s)" is not currently a reference
that would cause an implicit instantiation of X&lt;char&gt;::s.
This means you could use such a sizeof and later
specialize the static data member with a different size, meaning the earlier
sizeof gave the wrong result.  We could, of course, change the "use"
rules, but I'd rather see us require that static data members that
are arrays have a size specified in the class or have a size based
on their initializer.</P>

<P><B>Notes from the October 2003 meeting:</B></P>

<P>The example provided is valid according to the current
standard.  A static data member must be
instantiated (including the processing of its initializer, if any)
if there is any reference to it.  The compiler need not, however, put out
a definition in that translation unit.  The standard doesn't really
have a concept of a "partial instantiation" for a static data
member, and although we considered adding that, we decided that
to get all the size information that seems to be available one
needs a full instantiation in any case, so there's no need
for the concept of a partial instantiation.</P>

<P><B>Note (June, 2006):</B></P>

<P>Mark Mitchell suggested the following example:</P>

<PRE>
    template &lt;int&gt; void g();

    template &lt;typename T&gt;
    struct S {
      static int i[];
      void f();
    };

    template &lt;typename T&gt;
    int S&lt;T&gt;::i[] = { 1 };

    template &lt;typename T&gt;
    void S&lt;T&gt;::f() {
      g&lt;sizeof (i) / sizeof (int)&gt;();
    }

    template &lt;typename T&gt;
    int S&lt;int&gt;::i[] = { 1, 2 };
</PRE>

<P>Which <TT>g</TT> is called from <TT>S&lt;int&gt;::f()</TT>?</P>

<P>If the program is valid, then surely one would
expect <TT>g&lt;2&gt;</TT> to be called.</P>

<P>If the program is valid, does <TT>S&lt;T&gt;::i</TT> have a
non-dependent type in <TT>S&lt;T&gt;::f</TT>?  If so, is it
incomplete, or is it <TT>int[1]</TT>?  (Here, <TT>int[1]</TT> would be
surprising, since <TT>S&lt;int&gt;::i</TT> actually has
type <TT>int[2]</TT>.)</P>

<P>If the program is invalid, why?</P>

<P>For a simpler example, consider:</P>

<PRE>
    template &lt;typename T&gt;
    struct S {
      static int i[];
      const int N = sizeof (i);
    };
</PRE>

<P>This is only valid if the type of <TT>i</TT> is dependent,
meaning that the <TT>sizeof</TT> expression isn't evaluated until
the class is instantiated.</P>

<P><B>Proposed resolution (February, 2010):</B></P>

<OL>
<LI><P>Add the following as a new paragraph following
13.7.2.5 [<A href="https://wg21.link/temp.static#1">temp.static</A>] paragraph 1:</P></LI>

<BLOCKQUOTE>

<P><INS>An explicit specialization of a static data member declared as
an array of unknown bound can have a different bound from its
definition, if any. [<I>Example:</I></INS></P>

<PRE>
<INS>  template&lt;class T&gt; struct A {
    static int i[];
  };
  template&lt;class T&gt; int A&lt;T&gt;::i[4];    //<SPAN CLASS="cmnt"> 4 elements</SPAN>
  template&lt;&gt; int A&lt;int&gt;::i[] = { 1 };  //<SPAN CLASS="cmnt"> 1 element, OK</SPAN></INS>
</PRE>

<P><INS>&#8212;<I>end example</I>]</INS></P>

</BLOCKQUOTE>

<LI><P>Change 13.8.3.3 [<A href="https://wg21.link/temp.dep.expr#3">temp.dep.expr</A>] paragraph 3 as follows:</P></LI>

<BLOCKQUOTE>

<P>An <I>id-expression</I> is type-dependent if it contains<DEL>:</DEL>
</P>

<UL>
<LI><P>an <I>identifier</I> that was declared with a
dependent type,</P></LI>

<LI><P>a <I>template-id</I> that is dependent,</P></LI>

<LI><P>a <I>conversion-function-id</I> that specifies a dependent
type, <INS>or</INS>
</P></LI>

<LI><P>a <I>nested-name-specifier</I> or a <I>qualified-id</I>
that names a member of an unknown
specialization<DEL>.</DEL><INS>;</INS>
</P></LI>

</UL>

<P>
<INS>or if it names a static data member of the current
instantiation that has type &#8220;array of unknown bound of
<TT>T</TT>&#8221; for some <TT>T</TT> (13.7.2.5 [<A href="https://wg21.link/temp.static">temp.static</A>]).</INS> Expressions of the following forms are
type-dependent only if...</P>

</BLOCKQUOTE>

</OL>

<BR><BR>
</BODY>
</HTML>
