I fear that this is a bicycle shed issue. However I signed up in Kona to attempt to resolve this issue and this document reflects my commitment.
LWG issue 387 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.
There are two problems 387 is attempting to address:
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:
sizeof(complex<T>) == 2 * sizeof(T) &imag(z) == &real(z) + 1
Note: the above is not legal C++ code, it is just meant as a concise statement of the layout requirements.
And so the first goal of 387 does not appear to be controversial, and that part of the proposed resolution can simply be accepted.
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.
There are (at least) two motivating use cases for write access to the data members:
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:
Given:
void foo(double*, size_t); std::vector<std::complex<double> > v; ...
And given that the vector is not empty, here is the syntax a client might use for passing the vector to foo:
If a data() member function were to be added to vector then zero-sized vectors could be handled (without an explicit test) with:
foo(reinterpret_cast<double*>(v.data()), 2*v.size()); foo(complex_cast(v.data()), 2*v.size());
Given:
std::complex<double> z;
Here is how a client might assign 1.0 to the imaginary part of z:
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).