This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
simd<complex>::real/imag is overconstrainedSection: 29.10.8.4 [simd.complex.access] Status: WP Submitter: Matthias Kretz Opened: 2025-03-18 Last modified: 2025-11-11
Priority: 2
View all issues with WP status.
Discussion:
29.10.8.4 [simd.complex.access] overconstrains the arguments to real and imag.
complex<T>::real/imag allows conversions to T whereas simd<complex<T>>
requires basically an exact match (same_as<simd<T>> modulo ABI tag differences).
complex<double> c = {};
c.real(1.f); // OK
simd<complex<double>> sc = {};
sc.real(simd<float>(1.f)); // ill-formed, should be allowed
The design intent was to match the std::complex<T> interface. In which case
the current wording doesn't match that intent. complex doesn't say real(same_as<T> auto)
but 'real(T)', which allows conversions.
basic_simd(real, imag) constructor. It deduces the type for the
real/imag arguments instead of using a dependent type derived from value_type and ABI tag.
// OK:
complex<double> c{1., 1.f};
// Ill-formed, should be allowed:
simd<complex<double>> sc0(1., 1.);
simd<complex<double>, 4> sc1(simd<double, 4>(1.), simd<float, 4>(1.f));
[2025-06-13; Reflector poll]
Set priority to 2 after reflector poll.
Previous resolution [SUPERSEDED]:
This wording is relative to N5008.
Modify 29.10.7.1 [simd.overview], class template
basic_simdsynopsis, as indicated:namespace std::datapar { template<class T, class Abi> class basic_simd { public: using value_type = T; using mask_type = basic_simd_mask<sizeof(T), Abi>; using abi_type = Abi; using real-type = rebind_t<typename T::value_type, basic_simd> // exposition-only // 29.10.7.2 [simd.ctor], basic_simd constructors […]template<simd-floating-point V>constexpr explicit(see below) basic_simd(const real-typeV& reals, const real-typeV& imags = {}) noexcept; […] // 29.10.8.4 [simd.complex.access], basic_simd complex-value accessors constexpr real-typeautoreal() const noexcept; constexpr real-typeautoimag() const noexcept;template<simd-floating-point V>constexpr void real(const real-typeV& v) noexcept;template<simd-floating-point V>constexpr void imag(const real-typeV& v) noexcept; […] }; […] }Modify 29.10.7.2 [simd.ctor] as indicated:
template<simd-floating-point V>constexpr explicit(see below) basic_simd(const real-typeV& reals, const real-typeV& imags = {}) noexcept;-19- Constraints:
(19.1) —simd-complex<basic_simd>is modeled., and
(19.2) —V::size() == size()istrue.[…]
-21- Remarks: The expression insideexplicitevaluates tofalseif and only if the floating-point conversion rank ofT::value_typeis greater than or equal to the floating-point conversion rank ofreal-type.V::value_typeModify 29.10.8.4 [simd.complex.access] as indicated:
constexpr real-typeautoreal() const noexcept; constexpr real-typeautoimag() const noexcept;-1- Constraints:
-2- Returns: An object of typesimd-complex<basic_simd>is modeled.real-typewhere therebind_t<typename T::value_type, basic_simd>ith element is initialized to the result ofcmplx-func(operator[](i))for alliin the range[0, size()), wherecmplx-funcis the corresponding function from<complex>.template<simd-floating-point V>constexpr void real(const real-typeV& v) noexcept;template<simd-floating-point V>constexpr void imag(const real-typeV& v) noexcept;-3- Constraints:
(3.1) —simd-complex<basic_simd>is modeled.,
(3.2) —same_as<typename V::value_type, typename T::value_type>is modeled, and
(3.3) —V::size() == size()istrue.[…]
[2025-07-21; Matthias Kretz comments]
The currently shown P/R says:
Remarks: The expression inside
explicitevaluates tofalseif and only if the floating-point conversion rank ofT::value_typeis greater than or equal to the floating-point conversion rank ofreal-type::value_type.
But, by construction, real-type::value_type is the same as T::value_type.
So we get an elaborately worded explicit(false) here (which is correct).
Consequently, the proposed resolution needs to strike explicit(<i>see below</i>)
from 29.10.7.1 [simd.overview] and 29.10.7.2 [simd.ctor] and drop the Remarks paragraph (21).
[Kona 2025-11-04; approved by LWG. Status changed: New → Immediate.]
[Kona 2025-11-08; Status changed: Immediate → WP.]
Proposed resolution:
This wording is relative to N5014.
Modify 29.10.7.1 [simd.overview], class template basic_vec synopsis, as indicated:
namespace std::simd { template<class T, class Abi> class basic_vec { using real-type = see below; // exposition-only public: using value_type = T; using mask_type = basic_mask<sizeof(T), Abi>; using abi_type = Abi; using iterator = simd-iterator<basic_vec>; using const_iterator = simd-iterator<const basic_vec>; // 29.10.7.2 [simd.ctor], basic_vec constructors […]template<simd-floating-point V>constexprexplicit(see below)basic_vec(const real-typeV& reals, const real-typeV& imags = {}) noexcept; […] // 29.10.8.4 [simd.complex.access], basic_vec complex-value accessors constexpr real-typeautoreal() const noexcept; constexpr real-typeautoimag() const noexcept;template<simd-floating-point V>constexpr void real(const real-typeV& v) noexcept;template<simd-floating-point V>constexpr void imag(const real-typeV& v) noexcept; […] }; […] }-2- Recommended practice: […]
[Note 1: …]-?- If
Tis a specialization ofcomplex,real-typedenotes the same type asrebind_t<typename T::value_type, basic_vec<T, Abi>>, otherwise an unspecified non-array object type.
Modify 29.10.7.2 [simd.ctor] as indicated:
template<simd-floating-point V>constexprexplicit(see below)basic_vec(const real-typeV& reals, const real-typeV& imags = {}) noexcept;-19- Constraints:
(19.1) —simd-complex<basic_vec>is modeled., and
(19.2) —V::size() == size()istrue.[…]
-21- Remarks: The expression insideexplicitevaluates tofalseif and only if the floating-point conversion rank ofT::value_typeis greater than or equal to the floating-point conversion rank ofV::value_type.
Modify 29.10.8.4 [simd.complex.access] as indicated:
constexpr real-typeautoreal() const noexcept; constexpr real-typeautoimag() const noexcept;-1- Constraints:
-2- Returns: An object of typesimd-complex<basic_vec>is modeled.real-typewhere therebind_t<typename T::value_type, basic_vec>ith element is initialized to the result ofcmplx-func(operator[](i))for alliin the range[0, size()), wherecmplx-funcis the corresponding function from<complex>.template<simd-floating-point V>constexpr void real(const real-typeV& v) noexcept;template<simd-floating-point V>constexpr void imag(const real-typeV& v) noexcept;-3- Constraints:
(3.1) —simd-complex<basic_vec>is modeled.,
(3.2) —same_as<typename V::value_type, typename T::value_type>is modeled, and
(3.3) —V::size() == size()istrue.[…]