<!--This file created 2/11/04 2:15 PM by Claris Home Page version 2.0-->
<HTML>
<HEAD>
   <TITLE>complex issues</TITLE>
   <META NAME=GENERATOR CONTENT="Claris Home Page 2.0">
   <X-SAS-WINDOW TOP=49 BOTTOM=762 LEFT=177 RIGHT=707>
</HEAD>
<BODY BGCOLOR="#FFFFFF">

<ADDRESS>Document number: N1589=04-0029</ADDRESS>

<ADDRESS>&nbsp;</ADDRESS>

<ADDRESS>Howard E. Hinnant,
<A HREF="mailto:hinnant@twcny.rr.com">hinnant@twcny.rr.com</A>
</ADDRESS>

<ADDRESS>&nbsp;</ADDRESS>

<ADDRESS>February 11, 2004</ADDRESS>

<H1>complex and Issue 387</H1>

<P>I fear that this is a <I>bicycle shed</I> issue. However I signed
up in Kona to attempt to resolve this issue and this document
reflects my commitment.</P>

<P><A HREF="http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-active.html#387">LWG
issue 387</A> was heavily discussed on the lib reflector from Jan. 10
to Feb. 6, 2004. Many suggestions were made. In this paper I attempt
to collect and present the various suggestions. No conclusions are
reached nor recommendations made. It is hoped that an orderly
presentation of the different suggestions will aid discussion and
resolution. Apologies in advance for any suggestions which I may have
inadvertently mangled, or accidentally omitted altogether.</P>

<H2>Problem statement</H2>

<P>There are two problems 387 is attempting to address:</P>

<OL>
   <LI>Make complex&lt;T&gt; layout compatible with the complex data
   types of C and Fortran.
   
   <LI>Enable efficient write access to the individual parts (real
   and imaginary) of the complex type.
</OL>

<P>To the best of my knowledge, all existing implementations already
are layout compatible with C and Fortran. That is, the real part is
stored first, the imaginary part second, and the real and imaginary
parts occupy contiguous storage:</P>

<BLOCKQUOTE><PRE>sizeof(complex&lt;T&gt;) == 2 * sizeof(T)
&amp;imag(z) == &amp;real(z) + 1</PRE></BLOCKQUOTE>

<P>Note: the above is not legal C++ code, it is just meant as a
concise statement of the layout requirements.</P>

<P>And so the first goal of 387 does not appear to be controversial,
and that part of the proposed resolution can simply be accepted.</P>

<P>The second goal (write access to the data) seems to be where the
controversy is centered. Note that once the layout is standardized,
write access to the data members is granted, and it is just a matter
of what syntax the client is allowed to use in order to achieve
access.</P>

<P>There are (at least) two motivating use cases for write access to
the data members:</P>

<OL>
   <LI>Passing a vector&lt;complex&lt;double&gt; &gt; to legacy C or
   Fortran code.
   
   <LI>Assigning a value to one part of a complex without changing
   the other part.
</OL>

<H2>Options</H2>

<P>I will attempt to enumerate all of the options I have seen to
date, and show their syntax for the two motivating examples mentioned
above. The options are labeled 1-7:</P>

<OL>
   <LI>No change to the current interface (other than the layout
   guarantee).
   
   <LI>Return references from real() and imag() (as proposed in 387).
   
   <LI>Add a data() member function which returns a T* to the real
   part.
   
   <LI>Add a complex_cast function taking a complex&lt;T&gt;* and
   returning a T*.
   
   <LI>Add an operator[](size_t) which returns a reference to the
   data.
   
   <LI>Expose the data publicly as an array, say:<TT> T data[2];</TT>
   
   <LI>Get/Set functions, perhaps named real(T), imag(T).
</OL>

<H3>Example 1</H3>

<P>Given:</P>

<BLOCKQUOTE><PRE>void foo(double*, size_t);
std::vector&lt;std::complex&lt;double&gt; &gt; v;
...</PRE></BLOCKQUOTE>

<P>And given that the vector is not empty, here is the syntax a
client might use for passing the vector to foo:</P>

<OL>
   <LI><TT>foo(reinterpret_cast&lt;double*&gt;(&amp;v[0]),
   2*v.size());</TT>
   
   <LI><TT>foo(&amp;v[0].real(), 2*v.size());</TT>
   
   <LI><TT>foo(v[0].data(), 2*v.size());</TT>
   
   <LI><TT>foo(complex_cast(&amp;v[0]), 2*v.size());</TT>
   
   <LI><TT>foo(&amp;v[0][0], 2*v.size());</TT>
   
   <LI><TT>foo(&amp;v[0].data[0], 2*v.size());</TT>
   
   <LI><TT>foo(reinterpret_cast&lt;double*&gt;(&amp;v[0]),
   2*v.size());</TT>
</OL>

<P>If a data() member function were to be added to vector then
zero-sized vectors could be handled (without an explicit test) with:
</P>

<BLOCKQUOTE><PRE>foo(reinterpret_cast&lt;double*&gt;(v.data()), 2*v.size());
foo(complex_cast(v.data()), 2*v.size());</PRE></BLOCKQUOTE>

<H3>Example 2</H3>

<P>Given:</P>

<BLOCKQUOTE><PRE>std::complex&lt;double&gt; z;</PRE></BLOCKQUOTE>

<P>Here is how a client might assign 1.0 to the imaginary part of z:
</P>

<OL>
   <LI><TT>z = std::complex&lt;double&gt;(z.real(), 1.0);</TT>
   
   <LI><TT>z.imag() = 1.0;</TT>
   
   <LI><TT>*(z.data() + 1) = 1.0;</TT>
   
   <LI><TT>*(complex_cast(&amp;z) + 1) = 1.0;</TT>
   
   <LI><TT>z[1] = 1.0;</TT>
   
   <LI><TT>z.data[1] = 1.0;</TT>
   
   <LI><TT>z.imag(1.0);</TT>
</OL>

<P>A final note: We should realize that these suggestions are not
exclusive. For example we could adopt both 2 (real() returns a
reference) and 4 (complex_cast).</P>
</BODY>
</HTML>
