This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of CD1 status.

### 387. `std::complex` over-encapsulated

Section: 28.4 [complex.numbers] Status: CD1 Submitter: Gabriel Dos Reis Opened: 2002-11-08 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [complex.numbers].

View all issues with CD1 status.

Discussion:

The absence of explicit description of `std::complex<T>` layout makes it imposible to reuse existing software developed in traditional languages like Fortran or C with unambigous and commonly accepted layout assumptions. There ought to be a way for practitioners to predict with confidence the layout of `std::complex<T>` whenever `T` is a numerical datatype. The absence of ways to access individual parts of a `std::complex<T>` object as lvalues unduly promotes severe pessimizations. For example, the only way to change, independently, the real and imaginary parts is to write something like

    complex<T> z;
    // ...
    // set the real part to r
    z = complex<T>(r, z.imag());
    // ...
    // set the imaginary part to i
    z = complex<T>(z.real(), i);

At this point, it seems appropriate to recall that a complex number is, in effect, just a pair of numbers with no particular invariant to maintain. Existing practice in numerical computations has it that a complex number datatype is usually represented by Cartesian coordinates. Therefore the over-encapsulation put in the specification of `std::complex<>` is not justified.

Proposed resolution:

Add the following requirements to 28.4 [complex.numbers] as 26.3/4:

> If `z` is an lvalue expression of type cv `std::complex<T>` then

> - the expression `reinterpret_cast<cv T(&)[2]>(z)` is well-formed; and
> - `reinterpret_cast<cv T(&)[2]>(z)[0]` designates the real part of `z`; and
> - `reinterpret_cast<cv T(&)[2]>(z)[1]` designates the imaginary part of `z`.

> Moreover, if `a` is an expression of pointer type cv `complex<T>*` and the expression `a[i]` is well-defined for an integer expression `i` then:

> - `reinterpret_cast<cv T*>(a)[2*i]` designates the real part of `a[i]`; and
> - `reinterpret_cast<cv T*>(a)[2*i+1]` designates the imaginary part of `a[i]`.

In 28.4.3 [complex] and [complex.special] add the following member functions (changing `T` to concrete types as appropriate for the specializations).

>     void real(T);
>     void imag(T);

Add to 28.4.4 [complex.members]

>     T real() const;

> > Returns: the value of the real component

>     void real(T val);

> > Assigns `val` to the real component.

>     T imag() const;

> > Returns: the value of the imaginary component

>     void imag(T val);

> > Assigns `val` to the imaginary component.

[Kona: The layout guarantee is absolutely necessary for C compatibility. However, there was disagreement about the other part of this proposal: retrieving elements of the complex number as lvalues. An alternative: continue to have `real()` and `imag()` return rvalues, but add `set_real()` and `set_imag()`. Straw poll: return lvalues - 2, add setter functions - 5. Related issue: do we want reinterpret_cast as the interface for converting a complex to an array of two reals, or do we want to provide a more explicit way of doing it? Howard will try to resolve this issue for the next meeting.]

[pre-Sydney: Howard summarized the options in n1589.]

[ Bellevue: ]

> Second half of proposed wording replaced and moved to Ready.

[ Pre-Sophia Antipolis, Howard adds: ]

> Added the members to [complex.special] and changed from Ready to Review.

[ Post-Sophia Antipolis: ]

> Moved from WP back to Ready so that the "and [complex.special]" in the proposed resolution can be officially applied.

Rationale:

The LWG believes that C99 compatibility would be enough justification for this change even without other considerations. All existing implementations already have the layout proposed here.