Skip to content

Explicit construction of quantities using units that are not defined in system compiles but mathematically fails #59

@tsaubergine

Description

@tsaubergine

If I define a unit in a system that doesn't have this base dimension, e.g. angular_velocity in the degrees system:

quantity<unit<angular_velocity_dimension,degree::system>> angular_vel_deg(30*degree::degrees/si::seconds);

This compiles fine, and explicit conversions also compile fine:

quantity<unit<angular_velocity_dimension, si::system>> angular_vel_si(angular_vel_deg);

However when I go to run it, I get angular_vel_si as 30 rad/s rather than the expected 0.523 rad/s

The fact that this compiles seems to be a bug to me, but most importantly I'd like to be able to detect this situation (ideally with a static_assert) so that I don't have code that compiles but performs incorrect conversions.

With a few hours digging around I couldn't find a satisfactory way to do this, though I think it might be related to #36 but the proposed fix (#37) didn't fix my issue.

Here's my full minimal test case. Thanks in advance for any help you can provide:

#include "units/include/boost/units/systems/si.hpp"
#include "units/include/boost/units/systems/angle/degrees.hpp"
#include <cassert>
#include <iostream>
#include <cmath>


int main()
{
    double eps = std::numeric_limits<double>::epsilon();

    
    using boost::units::unit;
    using boost::units::quantity;
    namespace si = boost::units::si;
    namespace degree = boost::units::degree;

    // angle, works as expected
    {
        using boost::units::plane_angle_dimension;
        quantity<unit<plane_angle_dimension,degree::system>> angle_deg(30*degree::degrees);
        quantity<unit<plane_angle_dimension,si::system>> angle_si(angle_deg);

        std::cout << "Degrees: " << angle_deg.value() << ", radians: " << angle_si.value() << std::endl;

        assert(std::abs(angle_deg.value()-angle_si.value()) > eps);
    }
    
    // angular velocity: fails but more importantly, it compiles (when I feel that it shouldn't)
    {
        using boost::units::angular_velocity_dimension;

        quantity<unit<angular_velocity_dimension,degree::system>> angular_vel_deg(30*degree::degrees/si::seconds);
        quantity<unit<angular_velocity_dimension, si::system>> angular_vel_si(angular_vel_deg);

        std::cout << "Degrees/sec: " << angular_vel_deg.value() << ", radians/sec: " << angular_vel_si.value() << std::endl;
        
        assert(std::abs(angular_vel_deg.value()-angular_vel_si.value()) > eps);
    }
    
}

Output:

Degrees: 30, radians: 0.523599
Degrees/sec: 30, radians/sec: 30
a.out: test2.cpp:38: int main(): Assertion `std::abs(angular_vel_deg.value()-angular_vel_si.value()) > eps' failed.
zsh: IOT instruction (core dumped)  ./a.out

Expected (or compile failure would also be acceptable):

Degrees: 30, radians: 0.523599
Degrees/sec: 30, radians/sec: 0.523599

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions