Skip to content

PHYS_UNITS_COLLAPSE_TO_REP guarded with defined(...) prevents using dimensionless quantities (e.g., angles) even when set to 0 #18

@MasterElf

Description

@MasterElf

Summary

When trying to model angles as a dimensionless quantity (SI: radian is dimensionless), the library rejects quantity<dimensionless_d> with:

static_assert failed: 'quantity dimensions must not all be zero'

even if PHYS_UNITS_COLLAPSE_TO_REP is explicitly set to 0. The reason is that quantity.hpp uses #if defined(PHYS_UNITS_COLLAPSE_TO_REP) instead of a value check, so the assertion is enabled whenever the macro is defined (including when set to 0).

Affected code

In phys/units/quantity.hpp (current HEAD as of <insert date/commit>):

#ifndef  PHYS_UNITS_COLLAPSE_TO_REP
# define PHYS_UNITS_COLLAPSE_TO_REP  1
#endif

#if defined( PHYS_UNITS_COLLAPSE_TO_REP )
    static_assert( has_dimension, "quantity dimensions must not all be zero" );
#endif

Because the file defines the macro if it’s missing, defined(PHYS_UNITS_COLLAPSE_TO_REP) is always true, which trips the assert even when consumers pass -DPHYS_UNITS_COLLAPSE_TO_REP=0.

Minimal repro

// Build with: -DPHYS_UNITS_COLLAPSE_TO_REP=0
#include "phys/units/quantity.hpp"
using namespace phys::units;

struct EulerAngles
{
    quantity<dimensionless_d> roll{};
    quantity<dimensionless_d> pitch{};
    quantity<dimensionless_d> yaw{};
};

// Fails to compile with: static_assert failed: 'quantity dimensions must not all be zero'

Actual: Compilation fails with the static_assert.
Expected: With PHYS_UNITS_COLLAPSE_TO_REP=0, dimensionless quantities should be allowed (no collapse), so quantity<dimensionless_d> should compile.

Suggested fix

Switch the guard from macro-is-defined to a macro value check:

-#if defined( PHYS_UNITS_COLLAPSE_TO_REP )
+#if PHYS_UNITS_COLLAPSE_TO_REP
     static_assert( has_dimension, "quantity dimensions must not all be zero" );
 #endif

(Apply to all occurrences where the macro controls dimensionless handling.)
This preserves the current default (1 → collapse to representation type) while allowing consumers to opt out cleanly with PHYS_UNITS_COLLAPSE_TO_REP=0.

Workarounds

Patch quantity.hpp locally as above (or shadow the header earlier in the include path).

There is no reliable way to “undefine” the macro from user code because the header re-defines it via #ifndef.

Environment

Compiler: MSVC 19.xx (Visual Studio 2022)

C++ standard: C++20

OS: Windows 11

Build system: Unreal Engine 5.6 modules (but the repro above is plain C++)

Motivation / Context

Angles are naturally modeled as dimensionless in SI, but many users still want type safety via quantity<dimensionless_d>. Being able to set PHYS_UNITS_COLLAPSE_TO_REP=0 is important to keep angle quantities from collapsing to raw scalars. The current defined(...) check prevents that.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions