r/wg21
P3844R3 - Restore simd::vec broadcast from int WG21
Posted by u/simd_follower · 5 hr. ago

Document: P3844R3
Author: Matthias Kretz
Date: 2026-02-06
Audience: LWG
Target: C++26

The broadcast constructor in the Parallelism TS let you write vec<float>() + 1 and have it just work - the int got implicitly converted to float and broadcast across the vector. When simd merged into C++26 via P1928, the stricter value-preserving conversion rules made that expression ill-formed. This paper brings it back with a consteval constructor overload that checks at compile time whether the conversion loses precision, and rejects the program if it does.

The larger portion of the paper is actually a rewrite of [simd.math] - all the multi-argument math functions (hypot, pow, fma, lerp, etc.) need combinatorial overload expansions to avoid immediate-escalation from the consteval constructor. A 3-argument function like hypot goes from 1 overload to 7. LEWG gave strong consensus at Kona 2025, and LWG approved unanimously on the 2026-02-13 telecon.

▲ 28 points (89% upvoted) · 7 comments
sorted by: best
u/compile_time_enjoyer 31 points 4 hr. ago

TIL that vec<float>() + 1 is ill-formed in the C++26 CD. Worked in the TS for years. The committee giveth, the committee taketh away.

Glad someone noticed before we shipped it broken.

u/process_cynic_2023 19 points 3 hr. ago

The TS worked fine. Then Varna 2023 decided to drop the int exception from the broadcast constructor, planning on constant wrappers (std::cw<2>) instead. Three revisions later we're undoing that with a consteval workaround. Classic.

u/overload_resolution_victim 14 points 3 hr. ago

The consteval broadcast constructor itself is clean enough. What concerns me is the downstream cost to [simd.math].

for 3-arg math functions we would have to change to seven function templates

So every function like hypot(x, y, z), fma(x, y, z), lerp(a, b, t) gets seven overloads to cover all permutations of deduced-vec-t<V> vs bare V in each argument slot. For 2-arg functions it's three. This is a lot of surface area in [simd.syn] for what is fundamentally a workaround for the language not having constexpr function parameters.

Kretz himself says "making it more complicated is not warranted" and hopes P2826 expression aliases will let them simplify this in C++29. Which means we're shipping a known-temporary complexity expansion into the IS.

u/vectorized_for_lunch 8 points 2 hr. ago

The alternative is worse. Without the overload expansion, calling simd::hypot(x, 1) where x is a runtime vec triggers immediate-escalation of the whole function, which makes it require all arguments to be constant expressions. That kills the basic use case entirely.

The overload sets are ugly in the spec text but they're mechanically generated and the implementation burden is manageable. I'll take verbose wording over broken user code.

u/daily_segfault 9 points 2 hr. ago

Consteval constructors with constexpr exceptions to check value preservation at compile time. We are firmly in "the language is powerful enough to fix its own mistakes" territory and I'm not sure how to feel about that.

u/numeric_stability_matters 6 points 1 hr. ago

The Tony Table in section 3 is the whole motivation in four lines:

f(vec<double>()); // OK
// compiles but adds 99282960 instead of 99282957
f(vec<float>());
// compiles but adds infinity instead of 99282957
f(vec<std::float16_t>());

That's V(0x5EAF00D) silently giving you the wrong number because the explicit cast suppresses all warnings. With the consteval constructor, 0x5EAF00D passed directly to a vec<float> is ill-formed. Much better.

u/embedded_is_life_42 4 points 47 minutes ago

Has anyone actually shipped production code using std::experimental::simd from the TS? Genuine question. I've been using Highway for everything SIMD-related and haven't looked back.