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.

4391. Ambiguities of simd::basic_vec constructor

Section: 29.10.7.2 [simd.ctor] Status: New Submitter: Hewill Kang Opened: 2025-09-29 Last modified: 2025-10-03

Priority: Not Prioritized

View other active issues in [simd.ctor].

View all other issues in [simd.ctor].

View all issues with New status.

Discussion:

The broadcasting, generator-based, and range constructors of simd::basic_vec all take a single argument, and their constraints are not mutually exclusive.

This means that when a type satisfies both characteristics, such as a range that can be converted to a value_type, this will lead to ambiguity:

#include <simd>

struct S {
  operator double() const;       // basic_vec(U&& value)
  
  double operator()(int) const;  // basic_vec(G&& gen)

  double* begin() const;         // basic_vec(R&& r, flags<Flags...> = {});
  double* end() const;
  constexpr static int size() { return 2; }
};

int main() {
  std::simd::vec<double> simd(S{}); // error: call of overloaded 'basic_simd(S)' is ambiguous
}

Do we need more constraints, similar to the one in string_view(R&& r) that requires R not to be convertible to const char*, to make the above work, i.e., only invoke the broadcasting constructor?

Proposed resolution:

This wording is relative to N5014.

  1. Modify 29.10.7.2 [simd.ctor] as indicated:

    template<class G> constexpr explicit basic_vec(G&& gen);
    

    -8- Let Fromi denote the type decltype(gen(integral_constant<simd-size-type, i>())).

    -9- Constraints:

    1. (9.?) — constructible_from<value_type, G> is false.

    2. (9.?) — Fromi satisfies convertible_to<value_type> for all i in the range of [0, size()). In addition, for all i in the range of [0, size()), if Fromi is an arithmetic type, conversion from Fromi to value_type is value-preserving.

    […]
    template<class R, class... Flags>
      constexpr basic_vec(R&& r, flags<Flags...> = {});
    template<class R, class... Flags>
      constexpr basic_vec(R&& r, const mask_type& mask, flags<Flags...> = {});
    

    -12- Let mask be mask_type(true) for the overload with no mask parameter.

    -13- Constraints:

    1. (13.1) — R models ranges::contiguous_range and ranges::sized_range,

    2. (13.2) — ranges::size(r) is a constant expression, and

    3. (13.3) — ranges::size(r) is equal to size().,

    4. (13.?) — constructible_from<value_type, R> is false, and

    5. (13.?) — r(integral_constant<simd-size-type, 0>()) is not a valid expression.