v3.4.0: readable diagnostics (class-based named units) + #357 fix + natvis + error-msg CI harness - #358
Merged
Merged
Conversation
Upstream PR #356 (carlfriess:v3.x-fix-std-extension). The std:: math extensions (isnan/isinf/signbit) still called the removed unit operator() value accessor; switch them to raw(), add the missing std::isfinite overload, correct the doc comment (m() -> m.raw()), and add a macOS locale branch (BSD libc needs the canonical de_DE.UTF-8/en_US.UTF-8 spelling) to to_string_locale.
nholthaus
force-pushed
the
proto/strong-adl-357
branch
5 times, most recently
from
August 14, 2026 07:22
8a48f5c to
a777ab3
Compare
…print meters<double> Two linked readability wins for the v3.x unit type: 1. #357 (explicit-specialization-after-instantiation): forming an expression that reduces to a not-yet- included dimension (velocity/length -> 1/time) no longer breaks the build. traits::strong resolves the named strong type via an ADL customization point (detail::strong_name), not an explicit specialization of a class template — a later-included dimension header just contributes a better overload. 2. Named units (meters, hertz, square_meters, ...) are now CLASSES deriving from units::unit<...> instead of alias templates, so a compiler diagnostic prints the friendly 'meters<double>' instead of the 'unit<conversion_factor<...>, double, linear_scale>' soup — operands AND computed results. NO public API change: meters<>/meters<double> spell identically. The trait layer sees through / preserves the named type (detail::unit_base_t / is_named_unit_v / rewrap_to_named_t + the named_class_of ADL reverse map keyed on conversion_factor AND scale so linear vs decibel don't collide; replace_underlying, floating_point_promotion, std::common_type, std::hash, std::numeric_limits, arithmetic return types, to_string/operator<<, name()/abbreviation()). Pure dimensionless stays a plain alias (interchangeable with int/double).
…ression & coverage tests Harness (test/errorMessages): generate_cases.py emits 25 cases across the unit zoo (cross-dimension bad conversions, incompatible add/sub, derived-result mis-assignment, #357 include-ordering) + 4 curated = 29; run.py grades expected pass/fail + readable-named-type present + no conversion_factor soup, COMPILER-PORTABLE (MSVC cl /Zs + a normalize() so tokens match g++/clang/MSVC). Wired into all three CI workflows as an 'Error-message tests' step (MSVC job sets up cl via msvc-dev-cmd). Tests: namedUnitReportedTypeIsPreserved (arithmetic results named, math fns preserve name, traits see through the derived class, numeric_limits<Named> returns the named type, common_type<dimensioned-named,scalar> is SFINAE-empty, name()/abbreviation() incl. a compound unit, non-registered derived CF stays plain); unitsAsContainerKeys (units as std::map/set/unordered_map keys). unitLibTest 238/238; harness 29/29 on g++.
…opy) Show a unit as '3 m' / '5 mps' in Visual Studio Watch/Locals/DataTips instead of an opaque object. Adapted for this repo: type is units::unit<Cf,T,Scale> (not unit_t); magnitude is _linearized_value (not m_value); named units are classes deriving from units::unit<...> and natvis <Type> rules are inheritable, so the unit<*...> rules visualize a named unit through its base; linear_scale/decibel_scale are stateless here so the old scale-base rules are dropped. Abbreviation via an Optional func-eval intrinsic with a tag-name fallback. Wired into the INTERFACE target + install (MSVC-guarded, no-op elsewhere).
Sync the CMakeLists project() version (was stale at 3.1.2) to the v3.4.0 release.
nholthaus
force-pushed
the
proto/strong-adl-357
branch
from
August 14, 2026 07:32
a777ab3 to
279f12e
Compare
|
Readable compiler errors with concise typenames? That's a huge upgrade! Congrats on this improvement --- it's awesome to see. 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A readability + robustness release for the v3.x line — focused on what you see in the compiler and the
debugger. No public API changes:
meters<>/meters<double>and every unit spell exactly as before.1. Diagnostics name the unit, not the template soup
Named units are now classes deriving from
units::unit<...>(instead of alias templates), so a diagnosticreads
units::length::meters<double>→units::frequency::hertz<double>instead ofunit<conversion_factor<std::ratio<1>, dimension_t<...>>, double, linear_scale>— for both operands andcomputed results (
length*length→square_meters<double>, etc.). Rendering only; representation/values/API unchanged.
2. Fix #357 — include order no longer breaks the build
Forming an expression that reduces to a not-yet-included dimension (
velocity/length→1/time) failed with"explicit specialization after instantiation." The strong-type lookup is now an ADL customization point, so
a later-included header just adds a better overload — include order can't decide compilability.
3. Visual Studio natvis
natvis/units.natvisshows a unit as3 min Watch/Locals/DataTips; attached to the target + installed(MSVC-only, no-op elsewhere).
4.
std::math extensions (upstream PR #356 by @carlfriess, merged into this branch)std::isnan/isinf/signbitswitched off the removedoperator()toraw(); addsstd::isfinite; macOSlocale branch for the locale test.
Testing
unitLibTest238/238 green, incl. newnamedUnitReportedTypeIsPreserved+unitsAsContainerKeys.test/errorMessages/, 29 cases) grading readable-named-type presence andno-
conversion_factor-soup — compiler-portable (g++/clang/MSVC) and wired into all three CI workflows.Under the hood
Trait/
stdspecializations, arithmetic operators,to_string/operator<<,name()/abbreviation()allsee through / preserve the named class;
numeric_limits<Named>returns the named type;common_type <dimensioned-named, scalar>is SFINAE-empty (parity with the plain form); puredimensionlessstays a plainalias (interchangeable with int/double).
Version bumped to 3.4.0.