This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
Section: 29.10.9.1 [simd.mask.overview] Status: New Submitter: Arthur O'Dwyer Opened: 2025-10-02 Last modified: 2025-10-04
Priority: Not Prioritized
View all issues with New status.
Discussion:
29.10.9.1 [simd.mask.overview] has
namespace std::simd { template<class V> class simd-iterator { // exposition only V* data_ = nullptr; // exposition only simd-size-type offset_ = 0; // exposition only constexpr simd-iterator(V& d, simd-size-type off) noexcept; // exposition only […] }; […] template<size_t Bytes, class Abi> class basic_mask { public: using value_type = bool; using abi_type = Abi; using iterator = simd-iterator<basic_mask>; using const_iterator = simd-iterator<const basic_mask>; constexpr iterator begin() noexcept { return {*this, 0}; } constexpr const_iterator begin() const noexcept { return {*this, 0}; } constexpr const_iterator cbegin() const noexcept { return {*this, 0}; } constexpr default_sentinel_t end() const noexcept { return {}; } constexpr default_sentinel_t cend() const noexcept { return {}; } […]
It's unclear whether the "exposition-only" constructor is required to be present. If it is present,
as written, without explicit
, then {someBasicMask, 0}
becomes a valid initializer for an iterator.
Evidence in favor of its intentionality: the use of return {*this, 0}
in basic_mask::begin()
.
(The constructor is private
, but it still participates in overload resolution and will ambiguate
other possible conversions.) But this makes many expressions ambiguous that could be unambiguous to a human.
using Mask = std::simd::mask<int>; void overloaded(std::string, std::pair<Mask, int> kv); void overloaded(std::string, Mask::iterator it); int main() { Mask m; overloaded("the pair is", {m, 0}); // ambiguous? }
At the very least, we should say that this list-initialization is intentional, and add wording to
class simd-iterator
and/or remove the "exposition only" from simd-iterator
's
constructor. That makes it clear that the above program is indeed intended to be ambiguous. But IMO
we should instead simply make the above program valid.
Proposed resolution:
This wording is relative to N5014.
Modify 29.10.6 [simd.iterator] as indicated:
namespace std::simd { template<class V> class simd-iterator { // exposition only V* data_ = nullptr; // exposition only simd-size-type offset_ = 0; // exposition only constexpr explicit simd-iterator(V& d, simd-size-type off) noexcept; // exposition only […] }; }
Modify 29.10.7.1 [simd.overview] as indicated:
namespace std::simd { template<size_t T, class Abi> class basic_vec { 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>; constexpr iterator begin() noexcept { return iterator({*this, 0}); } constexpr const_iterator begin() const noexcept { return const_iterator({*this, 0}); } constexpr const_iterator cbegin() const noexcept { return const_iterator({*this, 0}); } constexpr default_sentinel_t end() const noexcept { return {}; } constexpr default_sentinel_t cend() const noexcept { return {}; } […] }; }
Modify 29.10.9.1 [simd.mask.overview] as indicated:
namespace std::simd { template<size_t Bytes, class Abi> class basic_mask { public: using value_type = bool; using abi_type = Abi; using iterator = simd-iterator<basic_mask>; using const_iterator = simd-iterator<const basic_mask>; constexpr iterator begin() noexcept { return iterator({*this, 0}); } constexpr const_iterator begin() const noexcept { return const_iterator({*this, 0}); } constexpr const_iterator cbegin() const noexcept { return const_iterator({*this, 0}); } constexpr default_sentinel_t end() const noexcept { return {}; } constexpr default_sentinel_t cend() const noexcept { return {}; } […] }; }