By using MPL metafunctions and the template specializations for operations
on composite dimensions (defined in boost/units/dimension.hpp)
it is possible to perform compile time arithmetic according to the dimensional
analysis rules described above
to produce new composite dimensions :

As a further demonstration of the flexibility of the system, we replace the
double value type with a std::complex<double> value type (ignoring the question of
the meaningfulness of complex lengths and energies) :

A generic function for computing mechanical work can be defined that takes
force and distance arguments in an arbitrary unit system and returns energy
in the same system:

/// the physical definition of work - computed for an arbitrary unit system template<classSystem,classY>quantity<unit<energy_dimension,System>,Y>work(quantity<unit<force_dimension,System>,Y>F,quantity<unit<length_dimension,System>,Y>dx){returnF*dx;}

/// the ideal gas law in si unitstemplate<classY>quantity<si::amount,Y>idealGasLaw(constquantity<si::pressure,Y>&P,constquantity<si::volume,Y>&V,constquantity<si::temperature,Y>&T){usingnamespaceboost::units::si;usingnamespaceconstants::codata;return(P*V/(R*T));}

Trigonometric and inverse trigonometric functions can be implemented for
any unit system that provides an angular base dimension. For radians, these
functions are found in boost/units/cmath.hpp
These behave as one expects, with trigonometric functions taking an angular
quantity and returning a dimensionless quantity, while the inverse trigonometric
functions take a dimensionless quantity and return an angular quantity :

User-defined value types that support the appropriate arithmetic operations
are automatically supported as quantity value types. The operators that
are supported by default for quantity value types are unary plus, unary
minus, addition, subtraction, multiplication, division, equal-to, not-equal-to,
less-than, less-or-equal-to, greater-than, and greater-or-equal-to. Support
for rational powers and roots can be added by overloading the power_typeof_helper
and root_typeof_helper
classes. Here we implement a user-defined measurement
class that models a numerical measurement with an associated measurement
error and the appropriate algebra and demonstrates its use as a quantity
value type; the full code is found in measurement.hpp.

illustrates implicit conversion of quantities of different value types where
implicit conversion of the value types themselves is allowed. N.B. The conversion
from double to int is treated as an explicit conversion because there is
no way to emulate the exact behavior of the built-in conversion. Explicit
constructors allow conversions for two cases:

This example demonstrates the use of boost::math::quaternion
as a value type for quantity
and the converse. For the first case, we first define specializations of
power_typeof_helper
and root_typeof_helper
for powers and roots, respectively:

so that all operations that are defined in the quaternion
class behave correctly. If rational powers were defined for this class, it
would be possible to compute rational powers and roots with no additional
changes.

Here, the unary plus and minus and addition and subtraction operators function
correctly. Unfortunately, the multiplication and division operations fail
because quaternion implements
them in terms of the *= and
/= operators, respectively,
which are incapable of representing the heterogeneous unit algebra needed
for quantities (an identical problem occurs with std::complex<T>,
for the same reason). In order to compute rational powers and roots, we need
to specialize power_typeof_helper
and root_typeof_helper
as follows:

This example demonstrates how to implement a replacement complex
class that functions correctly both as a quantity value type and as a quantity
container class, including heterogeneous multiplication and division operations
and rational powers and roots. Naturally, heterogeneous operations are only
supported on compilers that implement typeof.
The primary differences are that binary operations are not implemented using
the op=
operators and use the utility classes add_typeof_helper,
subtract_typeof_helper,
multiply_typeof_helper,
and divide_typeof_helper.
In addition, power_typeof_helper
and root_typeof_helper
are defined for both cases :

This example provides an ad hoc performance test to verify that zero runtime
overhead is incurred when using quantity
in place of double. Note that
performance optimization and testing is not trivial, so some care must be
taken in profiling. It is also critical to have a compiler capable of optimizing
the many template instantiations and inline calls effectively to achieve
maximal performance. Zero overhead for this test has been verified using
gcc 4.0.1, and icc 9.0, 10.0, and 10.1 on Mac OS 10.4 and 10.5, and using
msvc 8.0 on Windows XP.

These units include conversions between themselves and the meter. Three functions
for computing radar beam height from radar range and the local earth radius
are defined. The first takes arguments in one system and returns a value
in the same system :

The second is similar, but is templated on return type, so that the arguments
are converted to the return unit system internally :

template<classreturn_type,classSystem1,classSystem2,typenameT>return_typeradar_beam_height(constquantity<unit<length_dimension,System1>,T>&radar_range,constquantity<unit<length_dimension,System2>,T>&earth_radius,Tk=4.0/3.0){// need to decide which system to use for calculationconstreturn_typerr(radar_range),er(earth_radius);returnreturn_type(pow<2>(rr)/(2.0*k*er));}

Finally, the third function is an empirical approximation that is only valid
for radar ranges specified in nautical miles, returning beam height in feet.
This function uses the heterogeneous unit of nautical miles per square root
of feet to ensure dimensional correctness :

This example demonstrates using of absolute temperatures and relative temperature
differences in Fahrenheit and converting between these and the Kelvin temperature
scale. This issue touches on some surprisingly deep mathematical concepts
(see Wikipedia
for a basic review), but for our purposes here, we will simply observe that
it is important to be able to differentiate between an absolute temperature
measurement and a measurement of temperature difference. This is accomplished
by using the absolute
wrapper class.

The Boost.Units library does not require that the conversion factors be compile
time constants, as is demonstrated in this example:

usingboost::units::base_dimension;usingboost::units::base_unit;staticconstlongcurrency_base=1;structcurrency_base_dimension:base_dimension<currency_base_dimension,1>{};typedefcurrency_base_dimension::dimension_typecurrency_type;template<longN>structcurrency_base_unit:base_unit<currency_base_unit<N>,currency_type,currency_base+N>{};typedefcurrency_base_unit<0>us_dollar_base_unit;typedefcurrency_base_unit<1>euro_base_unit;typedefus_dollar_base_unit::unit_typeus_dollar;typedefeuro_base_unit::unit_typeeuro;// an array of all possible conversionsdoubleconversion_factors[2][2]={{1.0,1.0},{1.0,1.0}};doubleget_conversion_factor(longfrom,longto){return(conversion_factors[from][to]);}voidset_conversion_factor(longfrom,longto,doublevalue){conversion_factors[from][to]=value;conversion_factors[to][from]=1.0/value;}BOOST_UNITS_DEFINE_CONVERSION_FACTOR_TEMPLATE((longN1)(longN2),currency_base_unit<N1>,currency_base_unit<N2>,double,get_conversion_factor(N1,N2));

In this case, any unit that reduces to the overloaded unit will be output
with the replacement symbol.

Special names and symbols for the SI and CGS unit systems are found in boost/units/systems/si/io.hpp
and boost/units/systems/cgs/io.hpp,
respectively. If these headers are not included, the output will simply follow
default rules using the appropriate fundamental dimensions. Note that neither
of these functions is defined for quantities because doing so would require
making assumptions on how the corresponding value type should be formatted.

Three ostream formatters,
symbol_format, name_format, and typename_format
are provided for convenience. These select the textual representation of
units provided by symbol_string
or name_string in the first
two cases, while the latter returns a demangled typename for debugging purposes.
Formatting of scaled unit is also done correctly.

The iostream manipulators engineering_prefixes
or binary_prefixes make this
easy.

usingboost::units::binary_prefix;usingboost::units::engineering_prefix;usingboost::units::no_prefix;quantity<length>l=2.345*meters;// A quantity of length, in units of meters.cout<<engineering_prefix<<l<<endl;// Outputs "2.345 m".l=1000.0*l;// Increase it by 1000, so expect a k prefix.// Note that a double 1000.0 is required - an integer will fail to compile.cout<<engineering_prefix<<l<<endl;// Output autoprefixed with k to "2.345 km".quantity<energy>e=kilograms*pow<2>(l/seconds);// A quantity of energy.cout<<engineering_prefix<<e<<endl;// 5.49902 MJcout<<name_format<<engineering_prefix<<e<<endl;// 5.49902 megaJoule

This scale is specified in IEC 60027-2, Second edition, 2000-11, Letter symbols
to be used in electrical technology - Part 2: Telecommunications and electronics).

// Don't forget that the units name or symbol format specification is persistent.cout<<symbol_format<<endl;// Resets the format to the default symbol format.quantity<byte_base_unit::unit_type>b=2048.*byte_base_unit::unit_type();cout<<engineering_prefix<<b<<endl;// 2.048 kbcout<<symbol_format<<binary_prefix<<b<<endl;// "2 Kib"

But note that scalar dimensionless values, like int, float and double, are
not prefixed automatically by the engineering_prefix
or binary_prefix iostream manipulators.

You can output the name or symbol of a unit (rather than the most common
quantity of a unit).

constlengthL;// A unit of length (but not a quantity of length).cout<<L<<endl;// Default length unit is meter,// but default is symbol format so output is just "m".cout<<name_format<<L<<endl;// default length name is "meter".

Note too that all the formatting flags are persistent, so that if you set
engineering_prefix, then it applies to all future outputs, until you select
binary_prefix, or explicitly switch autoprefix off. You can specify no prefix
(the default of course) in two ways: