Millimeters in boost::units
Asked Answered
T

3

7

I want to use boost::units for some SI metrics. However our code mostly deals with millimeters and instead of using

quantity<length> value = 1*milli*meter;

we would prefer something like

quantity<length> value = 1*millimeter;

However I am not sure how to define "millimeter" (without using #define).

Secondly, what is the overhead in using prefixed units?

Update: This needs to run without C++11 features (i.e. no UDL)

Tal answered 6/2, 2013 at 7:53 Comment(0)
P
6

I am using the following approach:

// your namespace name for units
namespace outernamespace {
    namespace millimeter_system {
        typedef boost::units::scaled_base_unit<boost::units::si::meter_base_unit, boost::units::scale<10, boost::units::static_rational<-3>>> millimeter_base_unit;

        typedef boost::units::make_system<millimeter_base_unit>::type system;
        typedef boost::units::unit<boost::units::length_dimension, system> length;

        BOOST_UNITS_STATIC_CONSTANT(millimeter, length);
        BOOST_UNITS_STATIC_CONSTANT(millimeters, length);
    }

    typedef boost::units::quantity<millimeter_system::length> quantity_millimeter;
    using millimeter_system::millimeter;
    using millimeter_system::millimeters;
}

// demonstration of usage
void foo() {
    using namespace outernamespace;
    using namespace boost::units;
    using namespace boost::units::si;

    quantity_millimeter mm = 5 * millimeter;
    quantity<boost::units::si::length> m = 0.004 * meter;
    if (mm < static_cast<quantity_millimeter>(m)) {
        std::cout << 'lt ' << std::endl;
    }
    else {
        std::cout << 'geq ' << std::endl;
    }
}
Pasco answered 18/2, 2013 at 18:53 Comment(0)
N
13

C++11 is indeed the easiest solution. You could do

static const auto millimeter = milli * meter;

or

auto operator"" _mm (long double val) -> decltype(val * milli * meter)
{
     return val * milli * meter;
}

There should be no performance penalty as long as you are not converting to other prefixes. And even if you do it should be neglible.

If you don't want to use C++11 you'd need to find out the corresponding type of the expression milli * meter, though you could just replace auto by int and read the compiler message.

Nonreturnable answered 6/2, 2013 at 8:5 Comment(1)
It should be long double val (see en.cppreference.com/w/cpp/language/user_literal)Ezraezri
P
6

I am using the following approach:

// your namespace name for units
namespace outernamespace {
    namespace millimeter_system {
        typedef boost::units::scaled_base_unit<boost::units::si::meter_base_unit, boost::units::scale<10, boost::units::static_rational<-3>>> millimeter_base_unit;

        typedef boost::units::make_system<millimeter_base_unit>::type system;
        typedef boost::units::unit<boost::units::length_dimension, system> length;

        BOOST_UNITS_STATIC_CONSTANT(millimeter, length);
        BOOST_UNITS_STATIC_CONSTANT(millimeters, length);
    }

    typedef boost::units::quantity<millimeter_system::length> quantity_millimeter;
    using millimeter_system::millimeter;
    using millimeter_system::millimeters;
}

// demonstration of usage
void foo() {
    using namespace outernamespace;
    using namespace boost::units;
    using namespace boost::units::si;

    quantity_millimeter mm = 5 * millimeter;
    quantity<boost::units::si::length> m = 0.004 * meter;
    if (mm < static_cast<quantity_millimeter>(m)) {
        std::cout << 'lt ' << std::endl;
    }
    else {
        std::cout << 'geq ' << std::endl;
    }
}
Pasco answered 18/2, 2013 at 18:53 Comment(0)
B
-2

If you have a C++11 capable compiler you could use User Defined Literals for defining your units.

double operator"" _millimeter ( double value )
{
    return value;
}

You can use that like so:

double foo = 1000_millimeter;
Bootee answered 6/2, 2013 at 7:58 Comment(3)
But this is not "real" millimeters, but only a suffix attached. I.e. all the functionality of boost::units is gone. E.g. conversion between meter/millimeter, knowing that Area s = 1*millimeter * 1*millimeter is correct but Area s = 1 * 5 is not.Tal
Plus I need something that is not using UDL.Tal
But this can easily be combined with boost units by returning quantity<length> instead of doubleLitigate

© 2022 - 2024 — McMap. All rights reserved.