1 // Boost.Units - A C++ library for zero-overhead dimensional analysis and
2 // unit/quantity manipulation and conversion
3 //
4 // Copyright (C) 2003-2008 Matthias Christian Schabel
5 // Copyright (C) 2007-2008 Steven Watanabe
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See
8 // accompanying file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 
11 #ifndef BOOST_UNITS_CONVERSION_HPP
12 #define BOOST_UNITS_CONVERSION_HPP
13 
14 /// \file
15 /// \brief Template for defining conversions between quantities.
16 
17 #include <boost/units/detail/conversion_impl.hpp>
18 
19 namespace boost {
20 
21 namespace units {
22 
23 template<class From, class To>
24 struct conversion_helper;
25 
26 #ifdef BOOST_UNITS_DOXYGEN
27 
28 /// Template for defining conversions between
29 /// quantities.  This template should be specialized
30 /// for every quantity that allows conversions.
31 /// For example, if you have a two units
32 /// called pair and dozen you would write
33 /// @code
34 /// namespace boost {
35 /// namespace units {
36 /// template<class T0, class T1>
37 /// struct conversion_helper<quantity<dozen, T0>, quantity<pair, T1> >
38 /// {
39 ///     static quantity<pair, T1> convert(const quantity<dozen, T0>& source)
40 ///     {
41 ///         return(quantity<pair, T1>::from_value(6 * source.value()));
42 ///     }
43 /// };
44 /// }
45 /// }
46 /// @endcode
47 ///
48 /// In most cases, the predefined specializations for @c unit
49 /// and @c absolute should be sufficient, so users should rarely
50 /// need to use this.
51 template<class From, class To>
52 struct conversion_helper
53 {
54     static To convert(const From&);
55 };
56 
57 #endif
58 
59 /// Defines the conversion factor from a base unit to any unit
60 /// or to another base unit with the correct dimensions.  Uses
61 /// of this macro must appear at global scope.
62 /// If the destination unit is a base unit or a unit that contains
63 /// only one base unit which is raised to the first power (e.g. feet->meters)
64 /// the reverse (meters->feet in this example) need not be defined explicitly.
65 #define BOOST_UNITS_DEFINE_CONVERSION_FACTOR(Source, Destination, type_, value_)    \
66     namespace boost {                                                       \
67     namespace units {                                                       \
68     template<>                                                              \
69     struct select_base_unit_converter<                                      \
70         unscale<Source>::type,                                              \
71         unscale<reduce_unit<Destination::unit_type>::type>::type            \
72     >                                                                       \
73     {                                                                       \
74         typedef Source source_type;                                         \
75         typedef reduce_unit<Destination::unit_type>::type destination_type; \
76     };                                                                      \
77     template<>                                                              \
78     struct base_unit_converter<Source, reduce_unit<Destination::unit_type>::type>   \
79     {                                                                       \
80         static const bool is_defined = true;                                \
81         typedef type_ type;                                                 \
82         static type value() { return(value_); }                             \
83     };                                                                      \
84     }                                                                       \
85     }                                                                       \
86     void boost_units_require_semicolon()
87 
88 /// Defines the conversion factor from a base unit to any other base
89 /// unit with the same dimensions.  Params should be a Boost.Preprocessor
90 /// Seq of template parameters, such as (class T1)(class T2)
91 /// All uses of must appear at global scope. The reverse conversion will
92 /// be defined automatically.  This macro is a little dangerous, because,
93 /// unlike the non-template form, it will silently fail if either base
94 /// unit is scaled.  This is probably not an issue if both the source
95 /// and destination types depend on the template parameters, but be aware
96 /// that a generic conversion to kilograms is not going to work.
97 #define BOOST_UNITS_DEFINE_CONVERSION_FACTOR_TEMPLATE(Params, Source, Destination, type_, value_)   \
98     namespace boost {                                                       \
99     namespace units {                                                       \
100     template<BOOST_PP_SEQ_ENUM(Params)>                                     \
101     struct base_unit_converter<                                             \
102         Source,                                                             \
103         BOOST_UNITS_MAKE_HETEROGENEOUS_UNIT(Destination, typename Source::dimension_type)\
104     >                                                                       \
105     {                                                                       \
106         static const bool is_defined = true;                                \
107         typedef type_ type;                                                 \
108         static type value() { return(value_); }                             \
109     };                                                                      \
110     }                                                                       \
111     }                                                                       \
112     void boost_units_require_semicolon()
113 
114 /// Specifies the default conversion to be applied when
115 /// no direct conversion is available.
116 /// Source is a base unit.  Dest is any unit with the
117 /// same dimensions.
118 #define BOOST_UNITS_DEFAULT_CONVERSION(Source, Dest)                \
119     namespace boost {                                               \
120     namespace units {                                               \
121     template<>                                                      \
122     struct unscaled_get_default_conversion<unscale<Source>::type>   \
123     {                                                               \
124         static const bool is_defined = true;                        \
125         typedef Dest::unit_type type;                               \
126     };                                                              \
127     }                                                               \
128     }                                                               \
129     void boost_units_require_semicolon()
130 
131 /// Specifies the default conversion to be applied when
132 /// no direct conversion is available.
133 /// Params is a PP Sequence of template arguments.
134 /// Source is a base unit.  Dest is any unit with the
135 /// same dimensions.  The source must not be a scaled
136 /// base unit.
137 #define BOOST_UNITS_DEFAULT_CONVERSION_TEMPLATE(Params, Source, Dest)   \
138     namespace boost {                                                   \
139     namespace units {                                                   \
140     template<BOOST_PP_SEQ_ENUM(Params)>                                 \
141     struct unscaled_get_default_conversion<Source>                      \
142     {                                                                   \
143         static const bool is_defined = true;                            \
144         typedef typename Dest::unit_type type;                          \
145     };                                                                  \
146     }                                                                   \
147     }                                                                   \
148     void boost_units_require_semicolon()
149 
150 /// INTERNAL ONLY
151 /// Users should not create their units in namespace boost::units.
152 /// If we want to make this public it needs to allow better control over
153 /// the namespaces. --SJW.
154 /// template that defines a base_unit and conversion to another dimensionally-consistent unit
155 #define BOOST_UNITS_DEFINE_BASE_UNIT_WITH_CONVERSIONS(namespace_, name_, name_string_, symbol_string_, factor, unit, id)\
156 namespace boost {                                                           \
157 namespace units {                                                           \
158 namespace namespace_ {                                                      \
159 struct name_ ## _base_unit                                                  \
160   : base_unit<name_ ## _base_unit, unit::dimension_type, id> {              \
161     static const char* name() { return(name_string_); }                     \
162     static const char* symbol() { return(symbol_string_); };                \
163 };                                                                          \
164 }                                                                           \
165 }                                                                           \
166 }                                                                           \
167 BOOST_UNITS_DEFINE_CONVERSION_FACTOR(namespace_::name_ ## _base_unit, unit, double, factor); \
168 BOOST_UNITS_DEFAULT_CONVERSION(namespace_::name_ ## _base_unit, unit)
169 
170 /// Find the conversion factor between two units.
171 template<class FromUnit,class ToUnit>
172 inline
173 typename one_to_double_type<
174     typename detail::conversion_factor_helper<FromUnit, ToUnit>::type
175 >::type
conversion_factor(const FromUnit &,const ToUnit &)176 conversion_factor(const FromUnit&,const ToUnit&)
177 {
178     return(one_to_double(detail::conversion_factor_helper<FromUnit, ToUnit>::value()));
179 }
180 
181 } // namespace units
182 
183 } // namespace boost
184 
185 #endif // BOOST_UNITS_CONVERSION_HPP
186