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

4382. The simd::basic_mask(bool) overload needs to be more constrained

Section: 29.10.9.2 [simd.mask.ctor] Status: Tentatively Ready Submitter: Matthias Kretz Opened: 2025-09-24 Last modified: 2025-10-27

Priority: Not Prioritized

View all issues with Tentatively Ready status.

Discussion:

29.10.9.2 [simd.mask.ctor] defines the overloads basic_mask(bool) and basic_mask(unsigned_integral auto). This leads to the following pitfall:

auto g0() {
  unsigned short k = 0xf;
  return simd::mask<float, 8>(k); // mov eax, 15
}

auto g1() {
  unsigned short k = 0xf;
  return simd::mask<float, 8>(k >> 1); // mov eax, -1 ⚠️
}

auto g2() {
  unsigned int k = 0xf;
  return simd::mask<float, 8>(k >> 1); // mov eax, 7
}

In g1, k is promoted to int, shifted and then passed to the mask constructor. Instead of failing, int(0x7) is converted to bool and the mask thus initialized to all true.

Also consider:

  1. simd::mask<float>(true_type());

  2. unsigned_integral<bool> is true => same_as<bool> auto instead of 'bool' makes the overload set ambiguous

  3. float is convertible to bool, thus simd::mask<float>(1.f) continues to compile

Previous resolution [SUPERSEDED]:

This wording is relative to N5014.

  1. Modify 29.10.9.1 [simd.mask.overview], class template basic_mask synopsis, as indicated:

    namespace std::simd {
      template<size_t Bytes, class Abi> class basic_mask {
      public:
        […]
        
        constexpr basic_mask() noexcept = default;
        
        // 29.10.9.2 [simd.mask.ctor], basic_mask constructors
        constexpr explicit basic_mask(value_type) noexcept;
        template<size_t UBytes, class UAbi>
          constexpr explicit basic_mask(const basic_mask<UBytes, UAbi>&) noexcept;
        template<class G>
          constexpr explicit basic_mask(G&& gen) noexcept;
        constexpr basic_mask(const bitset<size()>& b) noexcept;
        constexpr explicit basic_mask(unsigned_integral auto val) noexcept;
        basic_mask(signed_integral auto) = delete;
        
        […]
      };
    }
    

[2025-10-06; Matthias Kretz improves wording after reflector discussion]

[2025-10-23; Reflector poll.]

Set status to Tentatively Ready after seven votes in favour during reflector poll.

Proposed resolution:

This wording is relative to N5014.

  1. Modify 29.10.9.1 [simd.mask.overview], class template basic_mask synopsis, as indicated:

    namespace std::simd {
      template<size_t Bytes, class Abi> class basic_mask {
      public:
        […]
        
        constexpr basic_mask() noexcept = default;
        
        // 29.10.9.2 [simd.mask.ctor], basic_mask constructors
        constexpr explicit basic_mask(same_as<value_type> auto) noexcept;
        template<size_t UBytes, class UAbi>
          constexpr explicit basic_mask(const basic_mask<UBytes, UAbi>&) noexcept;
        template<class G>
          constexpr explicit basic_mask(G&& gen) noexcept;
        template<same_as<bitset<size()>> T>
          constexpr basic_mask(const Tbitset<size()>& b) noexcept;
        template<unsigned_integral T> requires (!same_as<T, value_type>)
          constexpr explicit basic_mask(Tunsigned_integral auto val) noexcept;
        
        […]
      };
    }
    
  2. Modify 29.10.9.2 [simd.mask.ctor] as indicated:

    constexpr explicit basic_mask(same_as<value_type> auto x) noexcept;
    

    -1- Effects: Initializes each element with x.

    […]
    template<same_as<bitset<size()>> T>
      constexpr basic_mask(const Tbitset<size()>& b) noexcept;
    

    -7- Effects: Initializes the ith element with b[i] for all i in the range [0, size()).

    template<unsigned_integral T> requires (!same_as<T, value_type>)
      constexpr explicit basic_mask(Tunsigned_integral auto val) noexcept;
    

    -8- Effects: Initializes the first M elements to the corresponding bit values in val, […]