1137. Return type of conj and proj

Section: 29.4.10 [cmplx.over] Status: C++11 Submitter: Marc Steinbach Opened: 2009-06-11 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [cmplx.over].

View all issues with C++11 status.

Discussion:

In clause 1, the Working Draft (N2857) specifies overloads of the functions

arg, conj, imag, norm, proj, real

for non-complex arithmetic types (float, double, long double, and integers). The only requirement (clause 2) specifies effective type promotion of arguments.

I strongly suggest to add the following requirement on the return types:

All the specified overloads must return real (i.e., non-complex) values, specifically, the nested value_type of effectively promoted arguments.

(This has no effect on arg, imag, norm, real: they are real-valued anyway.)

Rationale:

Mathematically, conj() and proj(), like the transcendental functions, are complex-valued in general but map the (extended) real line to itself. In fact, both functions act as identity on the reals. A typical user will expect conj() and proj() to preserve this essential mathematical property in the same way as exp(), sin(), etc. A typical use of conj(), e.g., is the generic scalar product of n-vectors:

template<typename T>
inline T
scalar_product(size_t n, T const* x, T const* y) {
  T result = 0;
  for (size_t i = 0; i < n; ++i)
    result += x[i] * std::conj(y[i]);
  return result;
}

This will work equally well for real and complex floating-point types T if conj() returns T. It will not work with real types if conj() returns complex values.

Instead, the implementation of scalar_product becomes either less efficient and less useful (if a complex result is always returned), or unnecessarily complicated (if overloaded versions with proper return types are defined). In the second case, the real-argument overload of conj() cannot be used. In fact, it must be avoided.

Overloaded conj() and proj() are principally needed in generic programming. All such use cases will benefit from the proposed return type requirement, in a similar way as the scalar_product example. The requirement will not harm use cases where a complex return value is expected, because of implicit conversion to complex. Without the proposed return type guarantee, I find overloaded versions of conj() and proj() not only useless but actually troublesome.

[ 2009-11-11 Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]

Proposed resolution:

Insert a new paragraph after 29.4.10 [cmplx.over]/2:

All of the specified overloads shall have a return type which is the nested value_type of the effectively cast arguments.