1 //--------------------------------------------------------------------------------------------------
2 //
3 //	Units: A compile-time c++14 unit conversion library with no dependencies
4 //
5 //--------------------------------------------------------------------------------------------------
6 //
7 // The MIT License (MIT)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software
10 // and associated documentation files (the "Software"), to deal in the Software without
11 // restriction, including without limitation the rights to use, copy, modify, merge, publish,
12 // distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
14 //
15 // The above copyright notice and this permission notice shall be included in all copies or
16 // substantial portions of the Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
19 // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 //
24 //--------------------------------------------------------------------------------------------------
25 //
26 // Copyright (c) 2016 Nic Holthaus
27 //
28 //--------------------------------------------------------------------------------------------------
29 //
30 // ATTRIBUTION:
31 // Parts of this work have been adapted from:
32 // http://stackoverflow.com/questions/35069778/create-comparison-trait-for-template-classes-whose-parameters-are-in-a-different
33 // http://stackoverflow.com/questions/28253399/check-traits-for-all-variadic-template-arguments/28253503
34 // http://stackoverflow.com/questions/36321295/rational-approximation-of-square-root-of-stdratio-at-compile-time?noredirect=1#comment60266601_36321295
35 //
36 //--------------------------------------------------------------------------------------------------
37 //
38 /// @file	units.h
39 /// @brief	Complete implementation of `units` - a compile-time, header-only, unit conversion
40 ///			library built on c++14 with no dependencies.
41 //
42 //--------------------------------------------------------------------------------------------------
43 
44 #pragma once
45 
46 #ifndef units_h__
47 #define units_h__
48 
49 #ifdef _MSC_VER
50 #	pragma push_macro("pascal")
51 #	undef pascal
52 #	if _MSC_VER <= 1800
53 #		define _ALLOW_KEYWORD_MACROS
54 #		pragma warning(push)
55 #		pragma warning(disable : 4520)
56 #		pragma push_macro("constexpr")
57 #		define constexpr /*constexpr*/
58 #		pragma push_macro("noexcept")
59 #		define noexcept throw()
60 #	endif // _MSC_VER < 1800
61 #endif // _MSC_VER
62 
63 #if !defined(_MSC_VER) || _MSC_VER > 1800
64 #   define UNIT_HAS_LITERAL_SUPPORT
65 #   define UNIT_HAS_VARIADIC_TEMPLATE_SUPPORT
66 #endif
67 
68 #ifndef UNIT_LIB_DEFAULT_TYPE
69 #   define UNIT_LIB_DEFAULT_TYPE double
70 #endif
71 
72 //--------------------
73 //	INCLUDES
74 //--------------------
75 
76 #include <chrono>
77 #include <ratio>
78 #include <type_traits>
79 #include <cstdint>
80 #include <cmath>
81 #include <limits>
82 
83 #if !defined(UNIT_LIB_DISABLE_IOSTREAM)
84 	#include <iostream>
85 	#include <string>
86 	#include <locale>
87 
88 	//------------------------------
89 	//	STRING FORMATTER
90 	//------------------------------
91 
92 	namespace units
93 	{
94 		namespace detail
95 		{
to_string(const T & t)96 			template <typename T> std::string to_string(const T& t)
97 			{
98 				std::string str{ std::to_string(t) };
99 				int offset{ 1 };
100 
101 				// remove trailing decimal points for integer value units. Locale aware!
102 				struct lconv * lc;
103 				lc = localeconv();
104 				char decimalPoint = *lc->decimal_point;
105 				if (str.find_last_not_of('0') == str.find(decimalPoint)) { offset = 0; }
106 				str.erase(str.find_last_not_of('0') + offset, std::string::npos);
107 				return str;
108 			}
109 		}
110 	}
111 #endif
112 
113 namespace units
114 {
115 	template<typename T> inline constexpr const char* name(const T&);
116 	template<typename T> inline constexpr const char* abbreviation(const T&);
117 }
118 
119 //------------------------------
120 //	MACROS
121 //------------------------------
122 
123 /**
124  * @def			UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, definition)
125  * @brief		Helper macro for generating the boiler-plate code generating the tags of a new unit.
126  * @details		The macro generates singular, plural, and abbreviated forms
127  *				of the unit definition (e.g. `meter`, `meters`, and `m`), as aliases for the
128  *				unit tag.
129  * @param		namespaceName namespace in which the new units will be encapsulated.
130  * @param		nameSingular singular version of the unit name, e.g. 'meter'
131  * @param		namePlural - plural version of the unit name, e.g. 'meters'
132  * @param		abbreviation - abbreviated unit name, e.g. 'm'
133  * @param		definition - the variadic parameter is used for the definition of the unit
134  *				(e.g. `unit<std::ratio<1>, units::category::length_unit>`)
135  * @note		a variadic template is used for the definition to allow templates with
136  *				commas to be easily expanded. All the variadic 'arguments' should together
137  *				comprise the unit definition.
138  */
139 #define UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, /*definition*/...)\
140 	namespace namespaceName\
141 	{\
142 	/** @name Units (full names plural) */ /** @{ */ typedef __VA_ARGS__ namePlural; /** @} */\
143 	/** @name Units (full names singular) */ /** @{ */ typedef namePlural nameSingular; /** @} */\
144 	/** @name Units (abbreviated) */ /** @{ */ typedef namePlural abbreviation; /** @} */\
145 	}
146 
147 /**
148  * @def			UNIT_ADD_UNIT_DEFINITION(namespaceName,nameSingular)
149  * @brief		Macro for generating the boiler-plate code for the unit_t type definition.
150  * @details		The macro generates the definition of the unit container types, e.g. `meter_t`
151  * @param		namespaceName namespace in which the new units will be encapsulated.
152  * @param		nameSingular singular version of the unit name, e.g. 'meter'
153  */
154 #define UNIT_ADD_UNIT_DEFINITION(namespaceName,nameSingular)\
155 	namespace namespaceName\
156 	{\
157 		/** @name Unit Containers */ /** @{ */ typedef unit_t<nameSingular> nameSingular ## _t; /** @} */\
158 	}
159 
160 /**
161  * @def			UNIT_ADD_CUSTOM_TYPE_UNIT_DEFINITION(namespaceName,nameSingular,underlyingType)
162  * @brief		Macro for generating the boiler-plate code for a unit_t type definition with a non-default underlying type.
163  * @details		The macro generates the definition of the unit container types, e.g. `meter_t`
164  * @param		namespaceName namespace in which the new units will be encapsulated.
165  * @param		nameSingular singular version of the unit name, e.g. 'meter'
166  * @param		underlyingType the underlying type
167  */
168 #define UNIT_ADD_CUSTOM_TYPE_UNIT_DEFINITION(namespaceName,nameSingular, underlyingType)\
169 	namespace namespaceName\
170 	{\
171 	/** @name Unit Containers */ /** @{ */ typedef unit_t<nameSingular,underlyingType> nameSingular ## _t; /** @} */\
172 	}
173 /**
174  * @def			UNIT_ADD_IO(namespaceName,nameSingular, abbreviation)
175  * @brief		Macro for generating the boiler-plate code needed for I/O for a new unit.
176  * @details		The macro generates the code to insert units into an ostream. It
177  *				prints both the value and abbreviation of the unit when invoked.
178  * @param		namespaceName namespace in which the new units will be encapsulated.
179  * @param		nameSingular singular version of the unit name, e.g. 'meter'
180  * @param		abbrev - abbreviated unit name, e.g. 'm'
181  * @note		When UNIT_LIB_DISABLE_IOSTREAM is defined, the macro does not generate any code
182  */
183 #if defined(UNIT_LIB_DISABLE_IOSTREAM)
184 	#define UNIT_ADD_IO(namespaceName, nameSingular, abbrev)
185 #else
186 	#define UNIT_ADD_IO(namespaceName, nameSingular, abbrev)\
187 	namespace namespaceName\
188 	{\
189 		inline std::ostream& operator<<(std::ostream& os, const nameSingular ## _t& obj) \
190 		{\
191 			os << obj() << " "#abbrev; return os; \
192 		}\
193 		inline std::string to_string(const nameSingular ## _t& obj)\
194 		{\
195 			return units::detail::to_string(obj()) + std::string(" "#abbrev);\
196 		}\
197 	}
198 #endif
199 
200  /**
201   * @def		UNIT_ADD_NAME(namespaceName,nameSingular,abbreviation)
202   * @brief		Macro for generating constexpr names/abbreviations for units.
203   * @details	The macro generates names for units. E.g. name() of 1_m would be "meter", and
204   *				abbreviation would be "m".
205   * @param		namespaceName namespace in which the new units will be encapsulated. All literal values
206   *				are placed in the `units::literals` namespace.
207   * @param		nameSingular singular version of the unit name, e.g. 'meter'
208   * @param		abbreviation - abbreviated unit name, e.g. 'm'
209   */
210 #define UNIT_ADD_NAME(namespaceName, nameSingular, abbrev)\
211 template<> inline constexpr const char* name(const namespaceName::nameSingular ## _t&)\
212 {\
213 	return #nameSingular;\
214 }\
215 template<> inline constexpr const char* abbreviation(const namespaceName::nameSingular ## _t&)\
216 {\
217 	return #abbrev;\
218 }
219 
220 /**
221  * @def			UNIT_ADD_LITERALS(namespaceName,nameSingular,abbreviation)
222  * @brief		Macro for generating user-defined literals for units.
223  * @details		The macro generates user-defined literals for units. A literal suffix is created
224  *				using the abbreviation (e.g. `10.0_m`).
225  * @param		namespaceName namespace in which the new units will be encapsulated. All literal values
226  *				are placed in the `units::literals` namespace.
227  * @param		nameSingular singular version of the unit name, e.g. 'meter'
228  * @param		abbreviation - abbreviated unit name, e.g. 'm'
229  * @note		When UNIT_HAS_LITERAL_SUPPORT is not defined, the macro does not generate any code
230  */
231 #if defined(UNIT_HAS_LITERAL_SUPPORT)
232 	#define UNIT_ADD_LITERALS(namespaceName, nameSingular, abbreviation)\
233 	namespace literals\
234 	{\
235 		inline constexpr namespaceName::nameSingular ## _t operator""_ ## abbreviation(long double d)\
236 		{\
237 			return namespaceName::nameSingular ## _t(static_cast<namespaceName::nameSingular ## _t::underlying_type>(d));\
238 		}\
239 		inline constexpr namespaceName::nameSingular ## _t operator""_ ## abbreviation (unsigned long long d)\
240 		{\
241 			return namespaceName::nameSingular ## _t(static_cast<namespaceName::nameSingular ## _t::underlying_type>(d));\
242 		}\
243 	}
244 #else
245 	#define UNIT_ADD_LITERALS(namespaceName, nameSingular, abbreviation)
246 #endif
247 
248 /**
249  * @def			UNIT_ADD(namespaceName,nameSingular, namePlural, abbreviation, definition)
250  * @brief		Macro for generating the boiler-plate code needed for a new unit.
251  * @details		The macro generates singular, plural, and abbreviated forms
252  *				of the unit definition (e.g. `meter`, `meters`, and `m`), as well as the
253  *				appropriately named unit container (e.g. `meter_t`). A literal suffix is created
254  *				using the abbreviation (e.g. `10.0_m`). It also defines a class-specific
255  *				cout function which prints both the value and abbreviation of the unit when invoked.
256  * @param		namespaceName namespace in which the new units will be encapsulated. All literal values
257  *				are placed in the `units::literals` namespace.
258  * @param		nameSingular singular version of the unit name, e.g. 'meter'
259  * @param		namePlural - plural version of the unit name, e.g. 'meters'
260  * @param		abbreviation - abbreviated unit name, e.g. 'm'
261  * @param		definition - the variadic parameter is used for the definition of the unit
262  *				(e.g. `unit<std::ratio<1>, units::category::length_unit>`)
263  * @note		a variadic template is used for the definition to allow templates with
264  *				commas to be easily expanded. All the variadic 'arguments' should together
265  *				comprise the unit definition.
266  */
267 #define UNIT_ADD(namespaceName, nameSingular, namePlural, abbreviation, /*definition*/...)\
268 	UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, __VA_ARGS__)\
269 	UNIT_ADD_UNIT_DEFINITION(namespaceName,nameSingular)\
270 	UNIT_ADD_NAME(namespaceName,nameSingular, abbreviation)\
271 	UNIT_ADD_IO(namespaceName,nameSingular, abbreviation)\
272 	UNIT_ADD_LITERALS(namespaceName,nameSingular, abbreviation)
273 
274 /**
275  * @def			UNIT_ADD_WITH_CUSTOM_TYPE(namespaceName,nameSingular, namePlural, abbreviation, underlyingType, definition)
276  * @brief		Macro for generating the boiler-plate code needed for a new unit with a non-default underlying type.
277  * @details		The macro generates singular, plural, and abbreviated forms
278  *				of the unit definition (e.g. `meter`, `meters`, and `m`), as well as the
279  *				appropriately named unit container (e.g. `meter_t`). A literal suffix is created
280  *				using the abbreviation (e.g. `10.0_m`). It also defines a class-specific
281  *				cout function which prints both the value and abbreviation of the unit when invoked.
282  * @param		namespaceName namespace in which the new units will be encapsulated. All literal values
283  *				are placed in the `units::literals` namespace.
284  * @param		nameSingular singular version of the unit name, e.g. 'meter'
285  * @param		namePlural - plural version of the unit name, e.g. 'meters'
286  * @param		abbreviation - abbreviated unit name, e.g. 'm'
287  * @param		underlyingType - the underlying type, e.g. 'int' or 'float'
288  * @param		definition - the variadic parameter is used for the definition of the unit
289  *				(e.g. `unit<std::ratio<1>, units::category::length_unit>`)
290  * @note		a variadic template is used for the definition to allow templates with
291  *				commas to be easily expanded. All the variadic 'arguments' should together
292  *				comprise the unit definition.
293  */
294 #define UNIT_ADD_WITH_CUSTOM_TYPE(namespaceName, nameSingular, namePlural, abbreviation, underlyingType, /*definition*/...)\
295 	UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, __VA_ARGS__)\
296 	UNIT_ADD_CUSTOM_TYPE_UNIT_DEFINITION(namespaceName,nameSingular,underlyingType)\
297 	UNIT_ADD_IO(namespaceName,nameSingular, abbreviation)\
298 	UNIT_ADD_LITERALS(namespaceName,nameSingular, abbreviation)
299 
300 /**
301  * @def			UNIT_ADD_DECIBEL(namespaceName, nameSingular, abbreviation)
302  * @brief		Macro to create decibel container and literals for an existing unit type.
303  * @details		This macro generates the decibel unit container, cout overload, and literal definitions.
304  * @param		namespaceName namespace in which the new units will be encapsulated. All literal values
305  *				are placed in the `units::literals` namespace.
306  * @param		nameSingular singular version of the base unit name, e.g. 'watt'
307  * @param		abbreviation - abbreviated decibel unit name, e.g. 'dBW'
308  */
309 #define UNIT_ADD_DECIBEL(namespaceName, nameSingular, abbreviation)\
310 	namespace namespaceName\
311 	{\
312 		/** @name Unit Containers */ /** @{ */ typedef unit_t<nameSingular, UNIT_LIB_DEFAULT_TYPE, units::decibel_scale> abbreviation ## _t; /** @} */\
313 	}\
314 	UNIT_ADD_IO(namespaceName, abbreviation, abbreviation)\
315 	UNIT_ADD_LITERALS(namespaceName, abbreviation, abbreviation)
316 
317 /**
318  * @def			UNIT_ADD_CATEGORY_TRAIT(unitCategory, baseUnit)
319  * @brief		Macro to create the `is_category_unit` type trait.
320  * @details		This trait allows users to test whether a given type matches
321  *				an intended category. This macro comprises all the boiler-plate
322  *				code necessary to do so.
323  * @param		unitCategory The name of the category of unit, e.g. length or mass.
324  */
325 
326 #define UNIT_ADD_CATEGORY_TRAIT_DETAIL(unitCategory)\
327 	namespace traits\
328 	{\
329 		/** @cond */\
330 		namespace detail\
331 		{\
332 			template<typename T> struct is_ ## unitCategory ## _unit_impl : std::false_type {};\
333 			template<typename C, typename U, typename P, typename T>\
334 			struct is_ ## unitCategory ## _unit_impl<units::unit<C, U, P, T>> : std::is_same<units::traits::base_unit_of<typename units::traits::unit_traits<units::unit<C, U, P, T>>::base_unit_type>, units::category::unitCategory ## _unit>::type {};\
335 			template<typename U, typename S, template<typename> class N>\
336 			struct is_ ## unitCategory ## _unit_impl<units::unit_t<U, S, N>> : std::is_same<units::traits::base_unit_of<typename units::traits::unit_t_traits<units::unit_t<U, S, N>>::unit_type>, units::category::unitCategory ## _unit>::type {};\
337 		}\
338 		/** @endcond */\
339 	}
340 
341 #if defined(UNIT_HAS_VARIADIC_TEMPLATE_SUPPORT)
342 #define UNIT_ADD_IS_UNIT_CATEGORY_TRAIT(unitCategory)\
343 	namespace traits\
344 	{\
345 		template<typename... T> struct is_ ## unitCategory ## _unit : std::integral_constant<bool, units::all_true<units::traits::detail::is_ ## unitCategory ## _unit_impl<std::decay_t<T>>::value...>::value> {};\
346 	}
347 #else
348 #define UNIT_ADD_IS_UNIT_CATEGORY_TRAIT(unitCategory)\
349 	namespace traits\
350 	{\
351 			template<typename T1, typename T2 = T1, typename T3 = T1>\
352 			struct is_ ## unitCategory ## _unit : std::integral_constant<bool, units::traits::detail::is_ ## unitCategory ## _unit_impl<typename std::decay<T1>::type>::value &&\
353 				units::traits::detail::is_ ## unitCategory ## _unit_impl<typename std::decay<T2>::type>::value &&\
354 				units::traits::detail::is_ ## unitCategory ## _unit_impl<typename std::decay<T3>::type>::value>{};\
355 	}
356 #endif
357 
358 #define UNIT_ADD_CATEGORY_TRAIT(unitCategory)\
359 	UNIT_ADD_CATEGORY_TRAIT_DETAIL(unitCategory)\
360     /** @ingroup	TypeTraits*/\
361 	/** @brief		Trait which tests whether a type represents a unit of unitCategory*/\
362 	/** @details	Inherits from `std::true_type` or `std::false_type`. Use `is_ ## unitCategory ## _unit<T>::value` to test the unit represents a unitCategory quantity.*/\
363 	/** @tparam		T	one or more types to test*/\
364 	UNIT_ADD_IS_UNIT_CATEGORY_TRAIT(unitCategory)
365 
366 /**
367  * @def			UNIT_ADD_WITH_METRIC_PREFIXES(nameSingular, namePlural, abbreviation, definition)
368  * @brief		Macro for generating the boiler-plate code needed for a new unit, including its metric
369  *				prefixes from femto to peta.
370  * @details		See UNIT_ADD. In addition to generating the unit definition and containers '(e.g. `meters` and 'meter_t',
371  *				it also creates corresponding units with metric suffixes such as `millimeters`, and `millimeter_t`), as well as the
372  *				literal suffixes (e.g. `10.0_mm`).
373  * @param		namespaceName namespace in which the new units will be encapsulated. All literal values
374  *				are placed in the `units::literals` namespace.
375  * @param		nameSingular singular version of the unit name, e.g. 'meter'
376  * @param		namePlural - plural version of the unit name, e.g. 'meters'
377  * @param		abbreviation - abbreviated unit name, e.g. 'm'
378  * @param		definition - the variadic parameter is used for the definition of the unit
379  *				(e.g. `unit<std::ratio<1>, units::category::length_unit>`)
380  * @note		a variadic template is used for the definition to allow templates with
381  *				commas to be easily expanded. All the variadic 'arguments' should together
382  *				comprise the unit definition.
383  */
384 #define UNIT_ADD_WITH_METRIC_PREFIXES(namespaceName, nameSingular, namePlural, abbreviation, /*definition*/...)\
385 	UNIT_ADD(namespaceName, nameSingular, namePlural, abbreviation, __VA_ARGS__)\
386 	UNIT_ADD(namespaceName, femto ## nameSingular, femto ## namePlural, f ## abbreviation, femto<namePlural>)\
387 	UNIT_ADD(namespaceName, pico ## nameSingular, pico ## namePlural, p ## abbreviation, pico<namePlural>)\
388 	UNIT_ADD(namespaceName, nano ## nameSingular, nano ## namePlural, n ## abbreviation, nano<namePlural>)\
389 	UNIT_ADD(namespaceName, micro ## nameSingular, micro ## namePlural, u ## abbreviation, micro<namePlural>)\
390 	UNIT_ADD(namespaceName, milli ## nameSingular, milli ## namePlural, m ## abbreviation, milli<namePlural>)\
391 	UNIT_ADD(namespaceName, centi ## nameSingular, centi ## namePlural, c ## abbreviation, centi<namePlural>)\
392 	UNIT_ADD(namespaceName, deci ## nameSingular, deci ## namePlural, d ## abbreviation, deci<namePlural>)\
393 	UNIT_ADD(namespaceName, deca ## nameSingular, deca ## namePlural, da ## abbreviation, deca<namePlural>)\
394 	UNIT_ADD(namespaceName, hecto ## nameSingular, hecto ## namePlural, h ## abbreviation, hecto<namePlural>)\
395 	UNIT_ADD(namespaceName, kilo ## nameSingular, kilo ## namePlural, k ## abbreviation, kilo<namePlural>)\
396 	UNIT_ADD(namespaceName, mega ## nameSingular, mega ## namePlural, M ## abbreviation, mega<namePlural>)\
397 	UNIT_ADD(namespaceName, giga ## nameSingular, giga ## namePlural, G ## abbreviation, giga<namePlural>)\
398 	UNIT_ADD(namespaceName, tera ## nameSingular, tera ## namePlural, T ## abbreviation, tera<namePlural>)\
399 	UNIT_ADD(namespaceName, peta ## nameSingular, peta ## namePlural, P ## abbreviation, peta<namePlural>)\
400 
401  /**
402   * @def		UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(nameSingular, namePlural, abbreviation, definition)
403   * @brief		Macro for generating the boiler-plate code needed for a new unit, including its metric
404   *				prefixes from femto to peta, and binary prefixes from kibi to exbi.
405   * @details	See UNIT_ADD. In addition to generating the unit definition and containers '(e.g. `bytes` and 'byte_t',
406   *				it also creates corresponding units with metric suffixes such as `millimeters`, and `millimeter_t`), as well as the
407   *				literal suffixes (e.g. `10.0_B`).
408   * @param		namespaceName namespace in which the new units will be encapsulated. All literal values
409   *				are placed in the `units::literals` namespace.
410   * @param		nameSingular singular version of the unit name, e.g. 'byte'
411   * @param		namePlural - plural version of the unit name, e.g. 'bytes'
412   * @param		abbreviation - abbreviated unit name, e.g. 'B'
413   * @param		definition - the variadic parameter is used for the definition of the unit
414   *				(e.g. `unit<std::ratio<1>, units::category::data_unit>`)
415   * @note		a variadic template is used for the definition to allow templates with
416   *				commas to be easily expanded. All the variadic 'arguments' should together
417   *				comprise the unit definition.
418   */
419 #define UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(namespaceName, nameSingular, namePlural, abbreviation, /*definition*/...)\
420 	UNIT_ADD_WITH_METRIC_PREFIXES(namespaceName, nameSingular, namePlural, abbreviation, __VA_ARGS__)\
421 	UNIT_ADD(namespaceName, kibi ## nameSingular, kibi ## namePlural, Ki ## abbreviation, kibi<namePlural>)\
422 	UNIT_ADD(namespaceName, mebi ## nameSingular, mebi ## namePlural, Mi ## abbreviation, mebi<namePlural>)\
423 	UNIT_ADD(namespaceName, gibi ## nameSingular, gibi ## namePlural, Gi ## abbreviation, gibi<namePlural>)\
424 	UNIT_ADD(namespaceName, tebi ## nameSingular, tebi ## namePlural, Ti ## abbreviation, tebi<namePlural>)\
425 	UNIT_ADD(namespaceName, pebi ## nameSingular, pebi ## namePlural, Pi ## abbreviation, pebi<namePlural>)\
426 	UNIT_ADD(namespaceName, exbi ## nameSingular, exbi ## namePlural, Ei ## abbreviation, exbi<namePlural>)
427 
428 //--------------------
429 //	UNITS NAMESPACE
430 //--------------------
431 
432 /**
433  * @namespace units
434  * @brief Unit Conversion Library namespace
435  */
436 namespace units
437 {
438 	//----------------------------------
439 	//	DOXYGEN
440 	//----------------------------------
441 
442 	/**
443 	 * @defgroup	UnitContainers Unit Containers
444 	 * @brief		Defines a series of classes which contain dimensioned values. Unit containers
445 	 *				store a value, and support various arithmetic operations.
446 	 */
447 
448 	/**
449 	 * @defgroup	UnitTypes Unit Types
450 	 * @brief		Defines a series of classes which represent units. These types are tags used by
451 	 *				the conversion function, to create compound units, or to create `unit_t` types.
452 	 *				By themselves, they are not containers and have no stored value.
453 	 */
454 
455 	/**
456 	 * @defgroup	UnitManipulators Unit Manipulators
457 	 * @brief		Defines a series of classes used to manipulate unit types, such as `inverse<>`, `squared<>`, and metric prefixes.
458 	 *				Unit manipulators can be chained together, e.g. `inverse<squared<pico<time::seconds>>>` to
459 	 *				represent picoseconds^-2.
460 	 */
461 
462 	 /**
463 	  * @defgroup	CompileTimeUnitManipulators Compile-time Unit Manipulators
464 	  * @brief		Defines a series of classes used to manipulate `unit_value_t` types at compile-time, such as `unit_value_add<>`, `unit_value_sqrt<>`, etc.
465 	  *				Compile-time manipulators can be chained together, e.g. `unit_value_sqrt<unit_value_add<unit_value_power<a, 2>, unit_value_power<b, 2>>>` to
466 	  *				represent `c = sqrt(a^2 + b^2).
467 	  */
468 
469 	 /**
470 	 * @defgroup	UnitMath Unit Math
471 	 * @brief		Defines a collection of unit-enabled, strongly-typed versions of `<cmath>` functions.
472 	 * @details		Includes most c++11 extensions.
473 	 */
474 
475 	/**
476 	 * @defgroup	Conversion Explicit Conversion
477 	 * @brief		Functions used to convert values of one logical type to another.
478 	 */
479 
480 	/**
481 	 * @defgroup	TypeTraits Type Traits
482 	 * @brief		Defines a series of classes to obtain unit type information at compile-time.
483 	 */
484 
485 	//------------------------------
486 	//	FORWARD DECLARATIONS
487 	//------------------------------
488 
489 	/** @cond */	// DOXYGEN IGNORE
490 	namespace constants
491 	{
492 		namespace detail
493 		{
494 			static constexpr const UNIT_LIB_DEFAULT_TYPE PI_VAL = 3.14159265358979323846264338327950288419716939937510;
495 		}
496 	}
497 	/** @endcond */	// END DOXYGEN IGNORE
498 
499 	//------------------------------
500 	//	RATIO TRAITS
501 	//------------------------------
502 
503 	/**
504 	 * @ingroup TypeTraits
505 	 * @{
506 	 */
507 
508 	/** @cond */	// DOXYGEN IGNORE
509 	namespace detail
510 	{
511 		/// has_num implementation.
512 		template<class T>
513 		struct has_num_impl
514 		{
515 			template<class U>
testunits::detail::has_num_impl516 			static constexpr auto test(U*)->std::is_integral<decltype(U::num)> {return std::is_integral<decltype(U::num)>{}; }
517 			template<typename>
testunits::detail::has_num_impl518 			static constexpr std::false_type test(...) { return std::false_type{}; }
519 
520 			using type = decltype(test<T>(0));
521 		};
522 	}
523 
524 	/**
525 	 * @brief		Trait which checks for the existence of a static numerator.
526 	 * @details		Inherits from `std::true_type` or `std::false_type`. Use `has_num<T>::value` to test
527 	 *				whether `class T` has a numerator static member.
528 	 */
529 	template<class T>
530 	struct has_num : units::detail::has_num_impl<T>::type {};
531 
532 	namespace detail
533 	{
534 		/// has_den implementation.
535 		template<class T>
536 		struct has_den_impl
537 		{
538 			template<class U>
testunits::detail::has_den_impl539 			static constexpr auto test(U*)->std::is_integral<decltype(U::den)> { return std::is_integral<decltype(U::den)>{}; }
540 			template<typename>
testunits::detail::has_den_impl541 			static constexpr std::false_type test(...) { return std::false_type{}; }
542 
543 			using type = decltype(test<T>(0));
544 		};
545 	}
546 
547 	/**
548 	 * @brief		Trait which checks for the existence of a static denominator.
549 	 * @details		Inherits from `std::true_type` or `std::false_type`. Use `has_den<T>::value` to test
550 	 *				whether `class T` has a denominator static member.
551 	 */
552 	template<class T>
553 	struct has_den : units::detail::has_den_impl<T>::type {};
554 
555 	/** @endcond */	// END DOXYGEN IGNORE
556 
557 	namespace traits
558 	{
559 		/**
560 		 * @brief		Trait that tests whether a type represents a std::ratio.
561 		 * @details		Inherits from `std::true_type` or `std::false_type`. Use `is_ratio<T>::value` to test
562 		 *				whether `class T` implements a std::ratio.
563 		 */
564 		template<class T>
565 		struct is_ratio : std::integral_constant<bool,
566 			has_num<T>::value &&
567 			has_den<T>::value>
568 		{};
569 	}
570 
571 	//------------------------------
572 	//	UNIT TRAITS
573 	//------------------------------
574 
575 	/** @cond */	// DOXYGEN IGNORE
576 	/**
577 	 * @brief		void type.
578 	 * @details		Helper class for creating type traits.
579 	 */
580 	template<class ...>
581 	struct void_t { typedef void type; };
582 
583 	/**
584 	 * @brief		parameter pack for boolean arguments.
585 	 */
586 	template<bool...> struct bool_pack {};
587 
588 	/**
589 	 * @brief		Trait which tests that a set of other traits are all true.
590 	 */
591 	template<bool... Args>
592 	struct all_true : std::is_same<units::bool_pack<true, Args...>, units::bool_pack<Args..., true>> {};
593 	/** @endcond */	// DOXYGEN IGNORE
594 
595 	/**
596 	 * @brief namespace representing type traits which can access the properties of types provided by the units library.
597 	 */
598 	namespace traits
599 	{
600 #ifdef FOR_DOXYGEN_PURPOSES_ONLY
601 		/**
602 		 * @ingroup		TypeTraits
603 		 * @brief		Traits class defining the properties of units.
604 		 * @details		The units library determines certain properties of the units passed to
605 		 *				them and what they represent by using the members of the corresponding
606 		 *				unit_traits instantiation.
607 		 */
608 		template<class T>
609 		struct unit_traits
610 		{
611 			typedef typename T::base_unit_type base_unit_type;											///< Unit type that the unit was derived from. May be a `base_unit` or another `unit`. Use the `base_unit_of` trait to find the SI base unit type. This will be `void` if type `T` is not a unit.
612 			typedef typename T::conversion_ratio conversion_ratio;										///< `std::ratio` representing the conversion factor to the `base_unit_type`. This will be `void` if type `T` is not a unit.
613 			typedef typename T::pi_exponent_ratio pi_exponent_ratio;									///< `std::ratio` representing the exponent of pi to be used in the conversion. This will be `void` if type `T` is not a unit.
614 			typedef typename T::translation_ratio translation_ratio;									///< `std::ratio` representing a datum translation to the base unit (i.e. degrees C to degrees F conversion). This will be `void` if type `T` is not a unit.
615 		};
616 #endif
617 		/** @cond */	// DOXYGEN IGNORE
618 		/**
619 		 * @brief		unit traits implementation for classes which are not units.
620 		 */
621 		template<class T, typename = void>
622 		struct unit_traits
623 		{
624 			typedef void base_unit_type;
625 			typedef void conversion_ratio;
626 			typedef void pi_exponent_ratio;
627 			typedef void translation_ratio;
628 		};
629 
630 		template<class T>
631 		struct unit_traits
632 			<T, typename void_t<
633 			typename T::base_unit_type,
634 			typename T::conversion_ratio,
635 			typename T::pi_exponent_ratio,
636 			typename T::translation_ratio>::type>
637 		{
638 			typedef typename T::base_unit_type base_unit_type;											///< Unit type that the unit was derived from. May be a `base_unit` or another `unit`. Use the `base_unit_of` trait to find the SI base unit type. This will be `void` if type `T` is not a unit.
639 			typedef typename T::conversion_ratio conversion_ratio;										///< `std::ratio` representing the conversion factor to the `base_unit_type`. This will be `void` if type `T` is not a unit.
640 			typedef typename T::pi_exponent_ratio pi_exponent_ratio;									///< `std::ratio` representing the exponent of pi to be used in the conversion. This will be `void` if type `T` is not a unit.
641 			typedef typename T::translation_ratio translation_ratio;									///< `std::ratio` representing a datum translation to the base unit (i.e. degrees C to degrees F conversion). This will be `void` if type `T` is not a unit.
642 		};
643 		/** @endcond */	// END DOXYGEN IGNORE
644 	}
645 
646 	/** @cond */	// DOXYGEN IGNORE
647 	namespace detail
648 	{
649 		/**
650 		 * @brief		helper type to identify base units.
651 		 * @details		A non-templated base class for `base_unit` which enables RTTI testing.
652 		 */
653 		struct _base_unit_t {};
654 	}
655 	/** @endcond */	// END DOXYGEN IGNORE
656 
657 	namespace traits
658 	{
659 		/**
660 		 * @ingroup		TypeTraits
661 		 * @brief		Trait which tests if a class is a `base_unit` type.
662 		 * @details		Inherits from `std::true_type` or `std::false_type`. Use `is_base_unit<T>::value` to test
663 		 *				whether `class T` implements a `base_unit`.
664 		 */
665 		template<class T>
666 		struct is_base_unit : std::is_base_of<units::detail::_base_unit_t, T> {};
667 	}
668 
669 	/** @cond */	// DOXYGEN IGNORE
670 	namespace detail
671 	{
672 		/**
673 		 * @brief		helper type to identify units.
674 		 * @details		A non-templated base class for `unit` which enables RTTI testing.
675 		 */
676 		struct _unit {};
677 
678 		template<std::intmax_t Num, std::intmax_t Den = 1>
679 		using meter_ratio = std::ratio<Num, Den>;
680 	}
681 	/** @endcond */	// END DOXYGEN IGNORE
682 
683 	namespace traits
684 	{
685 		/**
686 		 * @ingroup		TypeTraits
687 		 * @brief		Traits which tests if a class is a `unit`
688 		 * @details		Inherits from `std::true_type` or `std::false_type`. Use `is_unit<T>::value` to test
689 		 *				whether `class T` implements a `unit`.
690 		 */
691 		template<class T>
692 		struct is_unit : std::is_base_of<units::detail::_unit, T>::type {};
693 	}
694 
695 	/** @} */ // end of TypeTraits
696 
697 	//------------------------------
698 	//	BASE UNIT CLASS
699 	//------------------------------
700 
701 	/**
702 	 * @ingroup		UnitTypes
703 	 * @brief		Class representing SI base unit types.
704 	 * @details		Base units are represented by a combination of `std::ratio` template parameters, each
705 	 *				describing the exponent of the type of unit they represent. Example: meters per second
706 	 *				would be described by a +1 exponent for meters, and a -1 exponent for seconds, thus:
707 	 *				`base_unit<std::ratio<1>, std::ratio<0>, std::ratio<-1>>`
708 	 * @tparam		Meter		`std::ratio` representing the exponent value for meters.
709 	 * @tparam		Kilogram	`std::ratio` representing the exponent value for kilograms.
710 	 * @tparam		Second		`std::ratio` representing the exponent value for seconds.
711 	 * @tparam		Radian		`std::ratio` representing the exponent value for radians. Although radians are not SI base units, they are included because radians are described by the SI as m * m^-1, which would make them indistinguishable from scalars.
712 	 * @tparam		Ampere		`std::ratio` representing the exponent value for amperes.
713 	 * @tparam		Kelvin		`std::ratio` representing the exponent value for Kelvin.
714 	 * @tparam		Mole		`std::ratio` representing the exponent value for moles.
715 	 * @tparam		Candela		`std::ratio` representing the exponent value for candelas.
716 	 * @tparam		Byte		`std::ratio` representing the exponent value for bytes.
717 	 * @sa			category	 for type aliases for SI base_unit types.
718 	 */
719 	template<class Meter = detail::meter_ratio<0>,
720 	class Kilogram = std::ratio<0>,
721 	class Second = std::ratio<0>,
722 	class Radian = std::ratio<0>,
723 	class Ampere = std::ratio<0>,
724 	class Kelvin = std::ratio<0>,
725 	class Mole = std::ratio<0>,
726 	class Candela = std::ratio<0>,
727 	class Byte = std::ratio<0>>
728 	struct base_unit : units::detail::_base_unit_t
729 	{
730 		static_assert(traits::is_ratio<Meter>::value, "Template parameter `Meter` must be a `std::ratio` representing the exponent of meters the unit has");
731 		static_assert(traits::is_ratio<Kilogram>::value, "Template parameter `Kilogram` must be a `std::ratio` representing the exponent of kilograms the unit has");
732 		static_assert(traits::is_ratio<Second>::value, "Template parameter `Second` must be a `std::ratio` representing the exponent of seconds the unit has");
733 		static_assert(traits::is_ratio<Ampere>::value, "Template parameter `Ampere` must be a `std::ratio` representing the exponent of amperes the unit has");
734 		static_assert(traits::is_ratio<Kelvin>::value, "Template parameter `Kelvin` must be a `std::ratio` representing the exponent of kelvin the unit has");
735 		static_assert(traits::is_ratio<Candela>::value, "Template parameter `Candela` must be a `std::ratio` representing the exponent of candelas the unit has");
736 		static_assert(traits::is_ratio<Mole>::value, "Template parameter `Mole` must be a `std::ratio` representing the exponent of moles the unit has");
737 		static_assert(traits::is_ratio<Radian>::value, "Template parameter `Radian` must be a `std::ratio` representing the exponent of radians the unit has");
738 		static_assert(traits::is_ratio<Byte>::value, "Template parameter `Byte` must be a `std::ratio` representing the exponent of bytes the unit has");
739 
740 		typedef Meter meter_ratio;
741 		typedef Kilogram kilogram_ratio;
742 		typedef Second second_ratio;
743 		typedef Radian radian_ratio;
744 		typedef Ampere ampere_ratio;
745 		typedef Kelvin kelvin_ratio;
746 		typedef Mole mole_ratio;
747 		typedef Candela candela_ratio;
748 		typedef Byte byte_ratio;
749 	};
750 
751 	//------------------------------
752 	//	UNIT CATEGORIES
753 	//------------------------------
754 
755 	/**
756 	 * @brief		namespace representing the implemented base and derived unit types. These will not generally be needed by library users.
757 	 * @sa			base_unit for the definition of the category parameters.
758 	 */
759 	namespace category
760 	{
761 		// SCALAR (DIMENSIONLESS) TYPES
762 		typedef base_unit<> scalar_unit;			///< Represents a quantity with no dimension.
763 		typedef base_unit<> dimensionless_unit;	///< Represents a quantity with no dimension.
764 
765 		// SI BASE UNIT TYPES
766 		//					METERS			KILOGRAMS		SECONDS			RADIANS			AMPERES			KELVIN			MOLE			CANDELA			BYTE		---		CATEGORY
767 		typedef base_unit<detail::meter_ratio<1>>																																		length_unit;			 		///< Represents an SI base unit of length
768 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<1>>																														mass_unit;				 		///< Represents an SI base unit of mass
769 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<0>,	std::ratio<1>>																										time_unit;				 		///< Represents an SI base unit of time
770 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<1>>																						angle_unit;				 		///< Represents an SI base unit of angle
771 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<1>>																		current_unit;			 		///< Represents an SI base unit of current
772 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<1>>														temperature_unit;		 		///< Represents an SI base unit of temperature
773 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<1>>										substance_unit;			 		///< Represents an SI base unit of amount of substance
774 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<1>>						luminous_intensity_unit; 		///< Represents an SI base unit of luminous intensity
775 
776 		// SI DERIVED UNIT TYPES
777 		//					METERS			KILOGRAMS		SECONDS			RADIANS			AMPERES			KELVIN			MOLE			CANDELA			BYTE		---		CATEGORY
778 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<2>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>>						solid_angle_unit;				///< Represents an SI derived unit of solid angle
779 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<0>,	std::ratio<-1>>																										frequency_unit;					///< Represents an SI derived unit of frequency
780 		typedef base_unit<detail::meter_ratio<1>,	std::ratio<0>,	std::ratio<-1>>																										velocity_unit;					///< Represents an SI derived unit of velocity
781 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<0>,	std::ratio<-1>,	std::ratio<1>>																						angular_velocity_unit;			///< Represents an SI derived unit of angular velocity
782 		typedef base_unit<detail::meter_ratio<1>,	std::ratio<0>,	std::ratio<-2>>																										acceleration_unit;				///< Represents an SI derived unit of acceleration
783 		typedef base_unit<detail::meter_ratio<1>,	std::ratio<1>,	std::ratio<-2>>																										force_unit;						///< Represents an SI derived unit of force
784 		typedef base_unit<detail::meter_ratio<-1>,	std::ratio<1>,	std::ratio<-2>>																										pressure_unit;					///< Represents an SI derived unit of pressure
785 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<0>,	std::ratio<1>,	std::ratio<0>,	std::ratio<1>>																		charge_unit;					///< Represents an SI derived unit of charge
786 		typedef base_unit<detail::meter_ratio<2>,	std::ratio<1>,	std::ratio<-2>>																										energy_unit;					///< Represents an SI derived unit of energy
787 		typedef base_unit<detail::meter_ratio<2>,	std::ratio<1>,	std::ratio<-3>>																										power_unit;						///< Represents an SI derived unit of power
788 		typedef base_unit<detail::meter_ratio<2>,	std::ratio<1>,	std::ratio<-3>,	std::ratio<0>,	std::ratio<-1>>																		voltage_unit;					///< Represents an SI derived unit of voltage
789 		typedef base_unit<detail::meter_ratio<-2>,	std::ratio<-1>,	std::ratio<4>,	std::ratio<0>,	std::ratio<2>>																		capacitance_unit;				///< Represents an SI derived unit of capacitance
790 		typedef base_unit<detail::meter_ratio<2>,	std::ratio<1>,	std::ratio<-3>,	std::ratio<0>,	std::ratio<-2>>																		impedance_unit;					///< Represents an SI derived unit of impedance
791 		typedef base_unit<detail::meter_ratio<-2>,	std::ratio<-1>,	std::ratio<3>,	std::ratio<0>,	std::ratio<2>>																		conductance_unit;				///< Represents an SI derived unit of conductance
792 		typedef base_unit<detail::meter_ratio<2>,	std::ratio<1>,	std::ratio<-2>,	std::ratio<0>,	std::ratio<-1>>																		magnetic_flux_unit;				///< Represents an SI derived unit of magnetic flux
793 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<1>,	std::ratio<-2>,	std::ratio<0>,	std::ratio<-1>>																		magnetic_field_strength_unit;	///< Represents an SI derived unit of magnetic field strength
794 		typedef base_unit<detail::meter_ratio<2>,	std::ratio<1>,	std::ratio<-2>,	std::ratio<0>,	std::ratio<-2>>																		inductance_unit;				///< Represents an SI derived unit of inductance
795 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<2>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<1>>						luminous_flux_unit;				///< Represents an SI derived unit of luminous flux
796 		typedef base_unit<detail::meter_ratio<-2>,	std::ratio<0>,	std::ratio<0>,	std::ratio<2>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<1>>						illuminance_unit;				///< Represents an SI derived unit of illuminance
797 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<0>,	std::ratio<-1>>																										radioactivity_unit;				///< Represents an SI derived unit of radioactivity
798 
799 		// OTHER UNIT TYPES
800 		//					METERS			KILOGRAMS		SECONDS			RADIANS			AMPERES			KELVIN			MOLE			CANDELA			BYTE		---		CATEGORY
801 		typedef base_unit<detail::meter_ratio<2>,	std::ratio<1>,	std::ratio<-2>>																										torque_unit;					///< Represents an SI derived unit of torque
802 		typedef base_unit<detail::meter_ratio<2>>																																		area_unit;						///< Represents an SI derived unit of area
803 		typedef base_unit<detail::meter_ratio<3>>																																		volume_unit;					///< Represents an SI derived unit of volume
804 		typedef base_unit<detail::meter_ratio<-3>,	std::ratio<1>>																														density_unit;					///< Represents an SI derived unit of density
805 		typedef base_unit<>																																						concentration_unit;				///< Represents a unit of concentration
806 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<1>>		data_unit;						///< Represents a unit of data size
807 		typedef base_unit<detail::meter_ratio<0>,	std::ratio<0>,	std::ratio<-1>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<0>,	std::ratio<1>>		data_transfer_rate_unit;		///< Represents a unit of data transfer rate
808 	}
809 
810 	//------------------------------
811 	//	UNIT CLASSES
812 	//------------------------------
813 
814 	/** @cond */	// DOXYGEN IGNORE
815 	/**
816 	 * @brief		unit type template specialization for units derived from base units.
817 	 */
818 	template <class, class, class, class> struct unit;
819 	template<class Conversion, class... Exponents, class PiExponent, class Translation>
820 	struct unit<Conversion, base_unit<Exponents...>, PiExponent, Translation> : units::detail::_unit
821 	{
822 		static_assert(traits::is_ratio<Conversion>::value, "Template parameter `Conversion` must be a `std::ratio` representing the conversion factor to `BaseUnit`.");
823 		static_assert(traits::is_ratio<PiExponent>::value, "Template parameter `PiExponent` must be a `std::ratio` representing the exponents of Pi the unit has.");
824 		static_assert(traits::is_ratio<Translation>::value, "Template parameter `Translation` must be a `std::ratio` representing an additive translation required by the unit conversion.");
825 
826 		typedef typename units::base_unit<Exponents...> base_unit_type;
827 		typedef Conversion conversion_ratio;
828 		typedef Translation translation_ratio;
829 		typedef PiExponent pi_exponent_ratio;
830 	};
831 	/** @endcond */	// END DOXYGEN IGNORE
832 
833 	/**
834 	 * @brief		Type representing an arbitrary unit.
835 	 * @ingroup		UnitTypes
836 	 * @details		`unit` types are used as tags for the `conversion` function. They are *not* containers
837 	 *				(see `unit_t` for a  container class). Each unit is defined by:
838 	 *
839 	 *				- A `std::ratio` defining the conversion factor to the base unit type. (e.g. `std::ratio<1,12>` for inches to feet)
840 	 *				- A base unit that the unit is derived from (or a unit category. Must be of type `unit` or `base_unit`)
841 	 *				- An exponent representing factors of PI required by the conversion. (e.g. `std::ratio<-1>` for a radians to degrees conversion)
842 	 *				- a ratio representing a datum translation required for the conversion (e.g. `std::ratio<32>` for a farenheit to celsius conversion)
843 	 *
844 	 *				Typically, a specific unit, like `meters`, would be implemented as a type alias
845 	 *				of `unit`, i.e. `using meters = unit<std::ratio<1>, units::category::length_unit`, or
846 	 *				`using inches = unit<std::ratio<1,12>, feet>`.
847 	 * @tparam		Conversion	std::ratio representing scalar multiplication factor.
848 	 * @tparam		BaseUnit	Unit type which this unit is derived from. May be a `base_unit`, or another `unit`.
849 	 * @tparam		PiExponent	std::ratio representing the exponent of pi required by the conversion.
850 	 * @tparam		Translation	std::ratio representing any datum translation required by the conversion.
851 	 */
852 	template<class Conversion, class BaseUnit, class PiExponent = std::ratio<0>, class Translation = std::ratio<0>>
853 	struct unit : units::detail::_unit
854 	{
855 		static_assert(traits::is_unit<BaseUnit>::value, "Template parameter `BaseUnit` must be a `unit` type.");
856 		static_assert(traits::is_ratio<Conversion>::value, "Template parameter `Conversion` must be a `std::ratio` representing the conversion factor to `BaseUnit`.");
857 		static_assert(traits::is_ratio<PiExponent>::value, "Template parameter `PiExponent` must be a `std::ratio` representing the exponents of Pi the unit has.");
858 
859 		typedef typename units::traits::unit_traits<BaseUnit>::base_unit_type base_unit_type;
860 		typedef typename std::ratio_multiply<typename BaseUnit::conversion_ratio, Conversion> conversion_ratio;
861 		typedef typename std::ratio_add<typename BaseUnit::pi_exponent_ratio, PiExponent> pi_exponent_ratio;
862 		typedef typename std::ratio_add<std::ratio_multiply<typename BaseUnit::conversion_ratio, Translation>, typename BaseUnit::translation_ratio> translation_ratio;
863 	};
864 
865 	//------------------------------
866 	//	BASE UNIT MANIPULATORS
867 	//------------------------------
868 
869 	/** @cond */	// DOXYGEN IGNORE
870 	namespace detail
871 	{
872 		/**
873 		 * @brief		base_unit_of trait implementation
874 		 * @details		recursively seeks base_unit type that a unit is derived from. Since units can be
875 		 *				derived from other units, the `base_unit_type` typedef may not represent this value.
876 		 */
877 		template<class> struct base_unit_of_impl;
878 		template<class Conversion, class BaseUnit, class PiExponent, class Translation>
879 		struct base_unit_of_impl<unit<Conversion, BaseUnit, PiExponent, Translation>> : base_unit_of_impl<BaseUnit> {};
880 		template<class... Exponents>
881 		struct base_unit_of_impl<base_unit<Exponents...>>
882 		{
883 			typedef base_unit<Exponents...> type;
884 		};
885 		template<>
886 		struct base_unit_of_impl<void>
887 		{
888 			typedef void type;
889 		};
890 	}
891 	/** @endcond */	// END DOXYGEN IGNORE
892 
893 	namespace traits
894 	{
895 		/**
896 		 * @brief		Trait which returns the `base_unit` type that a unit is originally derived from.
897 		 * @details		Since units can be derived from other `unit` types in addition to `base_unit` types,
898 		 *				the `base_unit_type` typedef will not always be a `base_unit` (or unit category).
899 		 *				Since compatible
900 		 */
901 		template<class U>
902 		using base_unit_of = typename units::detail::base_unit_of_impl<U>::type;
903 	}
904 
905 	/** @cond */	// DOXYGEN IGNORE
906 	namespace detail
907 	{
908 		/**
909 		 * @brief		implementation of base_unit_multiply
910 		 * @details		'multiples' (adds exponent ratios of) two base unit types. Base units can be found
911 		 *				using `base_unit_of`.
912 		 */
913 		template<class, class> struct base_unit_multiply_impl;
914 		template<class... Exponents1, class... Exponents2>
915 		struct base_unit_multiply_impl<base_unit<Exponents1...>, base_unit<Exponents2...>> {
916 			using type = base_unit<std::ratio_add<Exponents1, Exponents2>...>;
917 		};
918 
919 		/**
920 		 * @brief		represents type of two base units multiplied together
921 		 */
922 		template<class U1, class U2>
923 		using base_unit_multiply = typename base_unit_multiply_impl<U1, U2>::type;
924 
925 		/**
926 		 * @brief		implementation of base_unit_divide
927 		 * @details		'dived' (subtracts exponent ratios of) two base unit types. Base units can be found
928 		 *				using `base_unit_of`.
929 		 */
930 		template<class, class> struct base_unit_divide_impl;
931 		template<class... Exponents1, class... Exponents2>
932 		struct base_unit_divide_impl<base_unit<Exponents1...>, base_unit<Exponents2...>> {
933 			using type = base_unit<std::ratio_subtract<Exponents1, Exponents2>...>;
934 		};
935 
936 		/**
937 		 * @brief		represents the resulting type of `base_unit` U1 divided by U2.
938 		 */
939 		template<class U1, class U2>
940 		using base_unit_divide = typename base_unit_divide_impl<U1, U2>::type;
941 
942 		/**
943 		 * @brief		implementation of inverse_base
944 		 * @details		multiplies all `base_unit` exponent ratios by -1. The resulting type represents
945 		 *				the inverse base unit of the given `base_unit` type.
946 		 */
947 		template<class> struct inverse_base_impl;
948 
949 		template<class... Exponents>
950 		struct inverse_base_impl<base_unit<Exponents...>> {
951 			using type = base_unit<std::ratio_multiply<Exponents, std::ratio<-1>>...>;
952 		};
953 
954 		/**
955 		 * @brief		represent the inverse type of `class U`
956 		 * @details		E.g. if `U` is `length_unit`, then `inverse<U>` will represent `length_unit^-1`.
957 		 */
958 		template<class U> using inverse_base = typename inverse_base_impl<U>::type;
959 
960 		/**
961 		 * @brief		implementation of `squared_base`
962 		 * @details		multiplies all the exponent ratios of the given class by 2. The resulting type is
963 		 *				equivalent to the given type squared.
964 		 */
965 		template<class U> struct squared_base_impl;
966 		template<class... Exponents>
967 		struct squared_base_impl<base_unit<Exponents...>> {
968 			using type = base_unit<std::ratio_multiply<Exponents, std::ratio<2>>...>;
969 		};
970 
971 		/**
972 		 * @brief		represents the type of a `base_unit` squared.
973 		 * @details		E.g. `squared<length_unit>` will represent `length_unit^2`.
974 		 */
975 		template<class U> using squared_base = typename squared_base_impl<U>::type;
976 
977 		/**
978 		 * @brief		implementation of `cubed_base`
979 		 * @details		multiplies all the exponent ratios of the given class by 3. The resulting type is
980 		 *				equivalent to the given type cubed.
981 		 */
982 		template<class U> struct cubed_base_impl;
983 		template<class... Exponents>
984 		struct cubed_base_impl<base_unit<Exponents...>> {
985 			using type = base_unit<std::ratio_multiply<Exponents, std::ratio<3>>...>;
986 		};
987 
988 		/**
989 		 * @brief		represents the type of a `base_unit` cubed.
990 		 * @details		E.g. `cubed<length_unit>` will represent `length_unit^3`.
991 		 */
992 		template<class U> using cubed_base = typename cubed_base_impl<U>::type;
993 
994 		/**
995 		 * @brief		implementation of `sqrt_base`
996 		 * @details		divides all the exponent ratios of the given class by 2. The resulting type is
997 		 *				equivalent to the square root of the given type.
998 		 */
999 		template<class U> struct sqrt_base_impl;
1000 		template<class... Exponents>
1001 		struct sqrt_base_impl<base_unit<Exponents...>> {
1002 			using type = base_unit<std::ratio_divide<Exponents, std::ratio<2>>...>;
1003 		};
1004 
1005 		/**
1006 		 * @brief		represents the square-root type of a `base_unit`.
1007 		 * @details		E.g. `sqrt<length_unit>` will represent `length_unit^(1/2)`.
1008 		 */
1009 		template<class U> using sqrt_base = typename sqrt_base_impl<U>::type;
1010 
1011 		/**
1012 		 * @brief		implementation of `cbrt_base`
1013 		 * @details		divides all the exponent ratios of the given class by 3. The resulting type is
1014 		 *				equivalent to the given type's cube-root.
1015 		 */
1016 		template<class U> struct cbrt_base_impl;
1017 		template<class... Exponents>
1018 		struct cbrt_base_impl<base_unit<Exponents...>> {
1019 			using type = base_unit<std::ratio_divide<Exponents, std::ratio<3>>...>;
1020 		};
1021 
1022 		/**
1023 		 * @brief		represents the cube-root type of a `base_unit` .
1024 		 * @details		E.g. `cbrt<length_unit>` will represent `length_unit^(1/3)`.
1025 		 */
1026 		template<class U> using cbrt_base = typename cbrt_base_impl<U>::type;
1027 	}
1028 	/** @endcond */	// END DOXYGEN IGNORE
1029 
1030 	//------------------------------
1031 	//	UNIT MANIPULATORS
1032 	//------------------------------
1033 
1034 	/** @cond */	// DOXYGEN IGNORE
1035 	namespace detail
1036 	{
1037 		/**
1038 		 * @brief		implementation of `unit_multiply`.
1039 		 * @details		multiplies two units. The base unit becomes the base units of each with their exponents
1040 		 *				added together. The conversion factors of each are multiplied by each other. Pi exponent ratios
1041 		 *				are added, and datum translations are removed.
1042 		 */
1043 		template<class Unit1, class Unit2>
1044 		struct unit_multiply_impl
1045 		{
1046 			using type = unit < std::ratio_multiply<typename Unit1::conversion_ratio, typename Unit2::conversion_ratio>,
1047 				base_unit_multiply <traits::base_unit_of<typename Unit1::base_unit_type>, traits::base_unit_of<typename Unit2::base_unit_type>>,
1048 				std::ratio_add<typename Unit1::pi_exponent_ratio, typename Unit2::pi_exponent_ratio>,
1049 				std::ratio < 0 >> ;
1050 		};
1051 
1052 		/**
1053 		 * @brief		represents the type of two units multiplied together.
1054 		 * @details		recalculates conversion and exponent ratios at compile-time.
1055 		 */
1056 		template<class U1, class U2>
1057 		using unit_multiply = typename unit_multiply_impl<U1, U2>::type;
1058 
1059 		/**
1060 		 * @brief		implementation of `unit_divide`.
1061 		 * @details		divides two units. The base unit becomes the base units of each with their exponents
1062 		 *				subtracted from each other. The conversion factors of each are divided by each other. Pi exponent ratios
1063 		 *				are subtracted, and datum translations are removed.
1064 		 */
1065 		template<class Unit1, class Unit2>
1066 		struct unit_divide_impl
1067 		{
1068 			using type = unit < std::ratio_divide<typename Unit1::conversion_ratio, typename Unit2::conversion_ratio>,
1069 				base_unit_divide<traits::base_unit_of<typename Unit1::base_unit_type>, traits::base_unit_of<typename Unit2::base_unit_type>>,
1070 				std::ratio_subtract<typename Unit1::pi_exponent_ratio, typename Unit2::pi_exponent_ratio>,
1071 				std::ratio < 0 >> ;
1072 		};
1073 
1074 		/**
1075 		 * @brief		represents the type of two units divided by each other.
1076 		 * @details		recalculates conversion and exponent ratios at compile-time.
1077 		 */
1078 		template<class U1, class U2>
1079 		using unit_divide = typename unit_divide_impl<U1, U2>::type;
1080 
1081 		/**
1082 		 * @brief		implementation of `inverse`
1083 		 * @details		inverts a unit (equivalent to 1/unit). The `base_unit` and pi exponents are all multiplied by
1084 		 *				-1. The conversion ratio numerator and denominator are swapped. Datum translation
1085 		 *				ratios are removed.
1086 		 */
1087 		template<class Unit>
1088 		struct inverse_impl
1089 		{
1090 			using type = unit < std::ratio<Unit::conversion_ratio::den, Unit::conversion_ratio::num>,
1091 				inverse_base<traits::base_unit_of<typename units::traits::unit_traits<Unit>::base_unit_type>>,
1092 				std::ratio_multiply<typename units::traits::unit_traits<Unit>::pi_exponent_ratio, std::ratio<-1>>,
1093 				std::ratio < 0 >> ;	// inverses are rates or change, the translation factor goes away.
1094 		};
1095 	}
1096 	/** @endcond */	// END DOXYGEN IGNORE
1097 
1098 	/**
1099 	 * @brief		represents the inverse unit type of `class U`.
1100 	 * @ingroup		UnitManipulators
1101 	 * @tparam		U	`unit` type to invert.
1102 	 * @details		E.g. `inverse<meters>` will represent meters^-1 (i.e. 1/meters).
1103 	 */
1104 	template<class U> using inverse = typename units::detail::inverse_impl<U>::type;
1105 
1106 	/** @cond */	// DOXYGEN IGNORE
1107 	namespace detail
1108 	{
1109 		/**
1110 		 * @brief		implementation of `squared`
1111 		 * @details		Squares the conversion ratio, `base_unit` exponents, pi exponents, and removes
1112 		 *				datum translation ratios.
1113 		 */
1114 		template<class Unit>
1115 		struct squared_impl
1116 		{
1117 			static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type.");
1118 			using Conversion = typename Unit::conversion_ratio;
1119 			using type = unit < std::ratio_multiply<Conversion, Conversion>,
1120 				squared_base<traits::base_unit_of<typename Unit::base_unit_type>>,
1121 				std::ratio_multiply<typename Unit::pi_exponent_ratio, std::ratio<2>>,
1122 				typename Unit::translation_ratio
1123 			> ;
1124 		};
1125 	}
1126 	/** @endcond */	// END DOXYGEN IGNORE
1127 
1128 	/**
1129 	 * @brief		represents the unit type of `class U` squared
1130 	 * @ingroup		UnitManipulators
1131 	 * @tparam		U	`unit` type to square.
1132 	 * @details		E.g. `square<meters>` will represent meters^2.
1133 	 */
1134 	template<class U>
1135 	using squared = typename units::detail::squared_impl<U>::type;
1136 
1137 	/** @cond */	// DOXYGEN IGNORE
1138 	namespace detail
1139 	{
1140 		/**
1141 			 * @brief		implementation of `cubed`
1142 			 * @details		Cubes the conversion ratio, `base_unit` exponents, pi exponents, and removes
1143 			 *				datum translation ratios.
1144 			 */
1145 		template<class Unit>
1146 		struct cubed_impl
1147 		{
1148 			static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type.");
1149 			using Conversion = typename Unit::conversion_ratio;
1150 			using type = unit < std::ratio_multiply<Conversion, std::ratio_multiply<Conversion, Conversion>>,
1151 				cubed_base<traits::base_unit_of<typename Unit::base_unit_type>>,
1152 				std::ratio_multiply<typename Unit::pi_exponent_ratio, std::ratio<3>>,
1153 				typename Unit::translation_ratio> ;
1154 		};
1155 	}
1156 	/** @endcond */	// END DOXYGEN IGNORE
1157 
1158 	/**
1159 	 * @brief		represents the type of `class U` cubed.
1160 	 * @ingroup		UnitManipulators
1161 	 * @tparam		U	`unit` type to cube.
1162 	 * @details		E.g. `cubed<meters>` will represent meters^3.
1163 	 */
1164 	template<class U>
1165 	using cubed = typename units::detail::cubed_impl<U>::type;
1166 
1167 	/** @cond */	// DOXYGEN IGNORE
1168 	namespace detail
1169 	{
1170 		//----------------------------------
1171 		//	RATIO_SQRT IMPLEMENTATION
1172 		//----------------------------------
1173 
1174 		using Zero = std::ratio<0>;
1175 		using One = std::ratio<1>;
1176 		template <typename R> using Square = std::ratio_multiply<R, R>;
1177 
1178 		// Find the largest std::integer N such that Predicate<N>::value is true.
1179 		template <template <std::intmax_t N> class Predicate, typename enabled = void>
1180 		struct BinarySearch {
1181 			template <std::intmax_t N>
1182 			struct SafeDouble_ {
1183 				static constexpr const std::intmax_t value = 2 * N;
1184 				static_assert(value > 0, "Overflows when computing 2 * N");
1185 			};
1186 
1187 			template <intmax_t Lower, intmax_t Upper, typename Condition1 = void, typename Condition2 = void>
1188 			struct DoubleSidedSearch_ : DoubleSidedSearch_<Lower, Upper,
1189 				std::integral_constant<bool, (Upper - Lower == 1)>,
1190 				std::integral_constant<bool, ((Upper - Lower>1 && Predicate<Lower + (Upper - Lower) / 2>::value))>> {};
1191 
1192 			template <intmax_t Lower, intmax_t Upper>
1193 			struct DoubleSidedSearch_<Lower, Upper, std::false_type, std::false_type> : DoubleSidedSearch_<Lower, Lower + (Upper - Lower) / 2> {};
1194 
1195 			template <intmax_t Lower, intmax_t Upper, typename Condition2>
1196 			struct DoubleSidedSearch_<Lower, Upper, std::true_type, Condition2> : std::integral_constant<intmax_t, Lower>{};
1197 
1198 			template <intmax_t Lower, intmax_t Upper, typename Condition1>
1199 			struct DoubleSidedSearch_<Lower, Upper, Condition1, std::true_type> : DoubleSidedSearch_<Lower + (Upper - Lower) / 2, Upper>{};
1200 
1201 			template <std::intmax_t Lower, class enabled1 = void>
1202 			struct SingleSidedSearch_ : SingleSidedSearch_<Lower, std::integral_constant<bool, Predicate<SafeDouble_<Lower>::value>::value>>{};
1203 
1204 			template <std::intmax_t Lower>
1205 			struct SingleSidedSearch_<Lower, std::false_type> : DoubleSidedSearch_<Lower, SafeDouble_<Lower>::value> {};
1206 
1207 			template <std::intmax_t Lower>
1208 			struct SingleSidedSearch_<Lower, std::true_type> : SingleSidedSearch_<SafeDouble_<Lower>::value>{};
1209 
1210 			static constexpr const std::intmax_t value = SingleSidedSearch_<1>::value;
1211  		};
1212 
1213 		template <template <std::intmax_t N> class Predicate>
1214 		struct BinarySearch<Predicate, std::enable_if_t<!Predicate<1>::value>> : std::integral_constant<std::intmax_t, 0>{};
1215 
1216 		// Find largest std::integer N such that N<=sqrt(R)
1217 		template <typename R>
1218 		struct Integer {
1219 			template <std::intmax_t N> using Predicate_ = std::ratio_less_equal<std::ratio<N>, std::ratio_divide<R, std::ratio<N>>>;
1220 			static constexpr const std::intmax_t value = BinarySearch<Predicate_>::value;
1221 		};
1222 
1223 		template <typename R>
1224 		struct IsPerfectSquare {
1225 			static constexpr const std::intmax_t DenSqrt_ = Integer<std::ratio<R::den>>::value;
1226 			static constexpr const std::intmax_t NumSqrt_ = Integer<std::ratio<R::num>>::value;
1227 			static constexpr const bool value =( DenSqrt_ * DenSqrt_ == R::den && NumSqrt_ * NumSqrt_ == R::num);
1228 			using Sqrt = std::ratio<NumSqrt_, DenSqrt_>;
1229 		};
1230 
1231 		// Represents sqrt(P)-Q.
1232 		template <typename Tp, typename Tq>
1233 		struct Remainder {
1234 			using P = Tp;
1235 			using Q = Tq;
1236 		};
1237 
1238 		// Represents 1/R = I + Rem where R is a Remainder.
1239 		template <typename R>
1240 		struct Reciprocal {
1241 			using P_ = typename R::P;
1242 			using Q_ = typename R::Q;
1243 			using Den_ = std::ratio_subtract<P_, Square<Q_>>;
1244 			using A_ = std::ratio_divide<Q_, Den_>;
1245 			using B_ = std::ratio_divide<P_, Square<Den_>>;
1246 			static constexpr const std::intmax_t I_ = (A_::num + Integer<std::ratio_multiply<B_, Square<std::ratio<A_::den>>>>::value) / A_::den;
1247 			using I = std::ratio<I_>;
1248 			using Rem = Remainder<B_, std::ratio_subtract<I, A_>>;
1249 		};
1250 
1251 		// Expands sqrt(R) to continued fraction:
1252 		// f(x)=C1+1/(C2+1/(C3+1/(...+1/(Cn+x)))) = (U*x+V)/(W*x+1) and sqrt(R)=f(Rem).
1253 		// The error |f(Rem)-V| = |(U-W*V)x/(W*x+1)| <= |U-W*V|*Rem <= |U-W*V|/I' where
1254 		// I' is the std::integer part of reciprocal of Rem.
1255 		template <typename Tr, std::intmax_t N>
1256 		struct ContinuedFraction {
1257 			template <typename T>
1258 			using Abs_ = std::conditional_t<std::ratio_less<T, Zero>::value, std::ratio_subtract<Zero, T>, T>;
1259 
1260 			using R = Tr;
1261 			using Last_ = ContinuedFraction<R, N - 1>;
1262 			using Reciprocal_ = Reciprocal<typename Last_::Rem>;
1263 			using Rem = typename Reciprocal_::Rem;
1264 			using I_ = typename Reciprocal_::I;
1265 			using Den_ = std::ratio_add<typename Last_::W, I_>;
1266 			using U = std::ratio_divide<typename Last_::V, Den_>;
1267 			using V = std::ratio_divide<std::ratio_add<typename Last_::U, std::ratio_multiply<typename Last_::V, I_>>, Den_>;
1268 			using W = std::ratio_divide<One, Den_>;
1269 			using Error = Abs_<std::ratio_divide<std::ratio_subtract<U, std::ratio_multiply<V, W>>, typename Reciprocal<Rem>::I>>;
1270 		};
1271 
1272 		template <typename Tr>
1273 		struct ContinuedFraction<Tr, 1> {
1274 			using R = Tr;
1275 			using U = One;
1276 			using V = std::ratio<Integer<R>::value>;
1277 			using W = Zero;
1278 			using Rem = Remainder<R, V>;
1279 			using Error = std::ratio_divide<One, typename Reciprocal<Rem>::I>;
1280 		};
1281 
1282 		template <typename R, typename Eps, std::intmax_t N = 1, typename enabled = void>
1283 		struct Sqrt_ : Sqrt_<R, Eps, N + 1> {};
1284 
1285 		template <typename R, typename Eps, std::intmax_t N>
1286 		struct Sqrt_<R, Eps, N, std::enable_if_t<std::ratio_less_equal<typename ContinuedFraction<R, N>::Error, Eps>::value>> {
1287 			using type = typename ContinuedFraction<R, N>::V;
1288 		};
1289 
1290 		template <typename R, typename Eps, typename enabled = void>
1291 		struct Sqrt {
1292 			static_assert(std::ratio_greater_equal<R, Zero>::value, "R can't be negative");
1293 		};
1294 
1295 		template <typename R, typename Eps>
1296 		struct Sqrt<R, Eps, std::enable_if_t<std::ratio_greater_equal<R, Zero>::value && IsPerfectSquare<R>::value>> {
1297 			using type = typename IsPerfectSquare<R>::Sqrt;
1298 		};
1299 
1300 		template <typename R, typename Eps>
1301 		struct Sqrt<R, Eps, std::enable_if_t<(std::ratio_greater_equal<R, Zero>::value && !IsPerfectSquare<R>::value)>> : Sqrt_<R, Eps>{};
1302 	}
1303 	/** @endcond */	// END DOXYGEN IGNORE
1304 
1305 	/**
1306 	 * @ingroup		TypeTraits
1307 	 * @brief		Calculate square root of a ratio at compile-time
1308 	 * @details		Calculates a rational approximation of the square root of the ratio. The error
1309 	 *				in the calculation is bounded by 1/epsilon (Eps). E.g. for the default value
1310 	 *				of 10000000000, the maximum error will be a/10000000000, or 1e-8, or said another way,
1311 	 *				the error will be on the order of 10^-9. Since these calculations are done at
1312 	 *				compile time, it is advisable to set epsilon to the highest value that does not
1313 	 *				cause an integer overflow in the calculation. If you can't compile `ratio_sqrt`
1314 	 *				due to overflow errors, reducing the value of epsilon sufficiently will correct
1315 	 *				the problem.\n\n
1316 	 *				`ratio_sqrt` is guaranteed to converge for all values of `Ratio` which do not
1317 	 *				overflow.
1318 	 * @note		This function provides a rational approximation, _NOT_ an exact value.
1319 	 * @tparam		Ratio	ratio to take the square root of. This can represent any rational value,
1320 	 *						_not_ just integers or values with integer roots.
1321 	 * @tparam		Eps		Value of epsilon, which represents the inverse of the maximum allowable
1322 	 *						error. This value should be chosen to be as high as possible before
1323 	 *						integer overflow errors occur in the compiler.
1324 	 */
1325 	template<typename Ratio, std::intmax_t Eps = 10000000000>
1326 	using ratio_sqrt = typename  units::detail::Sqrt<Ratio, std::ratio<1, Eps>>::type;
1327 
1328 	/** @cond */	// DOXYGEN IGNORE
1329 	namespace detail
1330 	{
1331 		/**
1332 		 * @brief		implementation of `sqrt`
1333 		 * @details		square roots the conversion ratio, `base_unit` exponents, pi exponents, and removes
1334 		 *				datum translation ratios.
1335 		 */
1336 		template<class Unit, std::intmax_t Eps>
1337 		struct sqrt_impl
1338 		{
1339 			static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type.");
1340 			using Conversion = typename Unit::conversion_ratio;
1341 			using type = unit <ratio_sqrt<Conversion, Eps>,
1342 				sqrt_base<traits::base_unit_of<typename Unit::base_unit_type>>,
1343 				std::ratio_divide<typename Unit::pi_exponent_ratio, std::ratio<2>>,
1344 				typename Unit::translation_ratio>;
1345 		};
1346 	}
1347 	/** @endcond */	// END DOXYGEN IGNORE
1348 
1349 	/**
1350 	 * @ingroup		UnitManipulators
1351 	 * @brief		represents the square root of type `class U`.
1352 	 * @details		Calculates a rational approximation of the square root of the unit. The error
1353 	 *				in the calculation is bounded by 1/epsilon (Eps). E.g. for the default value
1354 	 *				of 10000000000, the maximum error will be a/10000000000, or 1e-8, or said another way,
1355 	 *				the error will be on the order of 10^-9. Since these calculations are done at
1356 	 *				compile time, it is advisable to set epsilon to the highest value that does not
1357 	 *				cause an integer overflow in the calculation. If you can't compile `ratio_sqrt`
1358 	 *				due to overflow errors, reducing the value of epsilon sufficiently will correct
1359 	 *				the problem.\n\n
1360 	 *				`ratio_sqrt` is guaranteed to converge for all values of `Ratio` which do not
1361 	 *				overflow.
1362 	 * @tparam		U	`unit` type to take the square root of.
1363 	 * @tparam		Eps	Value of epsilon, which represents the inverse of the maximum allowable
1364 	 *					error. This value should be chosen to be as high as possible before
1365 	 *					integer overflow errors occur in the compiler.
1366 	 * @note		USE WITH CAUTION. The is an approximate value. In general, squared<sqrt<meter>> != meter,
1367 	 *				i.e. the operation is not reversible, and it will result in propogated approximations.
1368 	 *				Use only when absolutely necessary.
1369 	 */
1370 	template<class U, std::intmax_t Eps = 10000000000>
1371 	using square_root = typename units::detail::sqrt_impl<U, Eps>::type;
1372 
1373 	//------------------------------
1374 	//	COMPOUND UNITS
1375 	//------------------------------
1376 
1377 	/** @cond */	// DOXYGEN IGNORE
1378 	namespace detail
1379 	{
1380 		/**
1381 			 * @brief		implementation of compound_unit
1382 			 * @details		multiplies a variadic list of units together, and is inherited from the resulting
1383 			 *				type.
1384 			 */
1385 		template<class U, class... Us> struct compound_impl;
1386 		template<class U> struct compound_impl<U> { using type = U; };
1387 		template<class U1, class U2, class...Us>
1388 		struct compound_impl<U1, U2, Us...>
1389 			: compound_impl<unit_multiply<U1, U2>, Us...> {};
1390 	}
1391 	/** @endcond */	// END DOXYGEN IGNORE
1392 
1393 	/**
1394 	 * @brief		Represents a unit type made up from other units.
1395 	 * @details		Compound units are formed by multiplying the units of all the types provided in
1396 	 *				the template argument. Types provided must inherit from `unit`. A compound unit can
1397 	 *				be formed from any number of other units, and unit manipulators like `inverse` and
1398 	 *				`squared` are supported. E.g. to specify acceleration, on could create
1399 	 *				`using acceleration = compound_unit<length::meters, inverse<squared<seconds>>;`
1400 	 * @tparam		U...	units which, when multiplied together, form the desired compound unit.
1401 	 * @ingroup		UnitTypes
1402 	 */
1403 	template<class U, class... Us>
1404 	using compound_unit = typename units::detail::compound_impl<U, Us...>::type;
1405 
1406 	//------------------------------
1407 	//	PREFIXES
1408 	//------------------------------
1409 
1410 	/** @cond */	// DOXYGEN IGNORE
1411 	namespace detail
1412 	{
1413 		/**
1414 		 * @brief		prefix applicator.
1415 		 * @details		creates a unit type from a prefix and a unit
1416 		 */
1417 		template<class Ratio, class Unit>
1418 		struct prefix
1419 		{
1420 			static_assert(traits::is_ratio<Ratio>::value, "Template parameter `Ratio` must be a `std::ratio`.");
1421 			static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type.");
1422 			typedef typename units::unit<Ratio, Unit> type;
1423 		};
1424 
1425 		/// recursive exponential implementation
1426 		template <int N, class U>
1427 		struct power_of_ratio
1428 		{
1429 			typedef std::ratio_multiply<U, typename power_of_ratio<N - 1, U>::type> type;
1430 		};
1431 
1432 		/// End recursion
1433 		template <class U>
1434 		struct power_of_ratio<1, U>
1435 		{
1436 			typedef U type;
1437 		};
1438 	}
1439 	/** @endcond */	// END DOXYGEN IGNORE
1440 
1441 	/**
1442 	 * @ingroup UnitManipulators
1443 	 * @{
1444 	 * @ingroup Decimal Prefixes
1445 	 * @{
1446 	 */
1447 	template<class U> using atto	= typename units::detail::prefix<std::atto,	U>::type;			///< Represents the type of `class U` with the metric 'atto' prefix appended.	@details E.g. atto<meters> represents meters*10^-18		@tparam U unit type to apply the prefix to.
1448 	template<class U> using femto	= typename units::detail::prefix<std::femto,U>::type;			///< Represents the type of `class U` with the metric 'femto' prefix appended.  @details E.g. femto<meters> represents meters*10^-15	@tparam U unit type to apply the prefix to.
1449 	template<class U> using pico	= typename units::detail::prefix<std::pico,	U>::type;			///< Represents the type of `class U` with the metric 'pico' prefix appended.	@details E.g. pico<meters> represents meters*10^-12		@tparam U unit type to apply the prefix to.
1450 	template<class U> using nano	= typename units::detail::prefix<std::nano,	U>::type;			///< Represents the type of `class U` with the metric 'nano' prefix appended.	@details E.g. nano<meters> represents meters*10^-9		@tparam U unit type to apply the prefix to.
1451 	template<class U> using micro	= typename units::detail::prefix<std::micro,U>::type;			///< Represents the type of `class U` with the metric 'micro' prefix appended.	@details E.g. micro<meters> represents meters*10^-6		@tparam U unit type to apply the prefix to.
1452 	template<class U> using milli	= typename units::detail::prefix<std::milli,U>::type;			///< Represents the type of `class U` with the metric 'milli' prefix appended.	@details E.g. milli<meters> represents meters*10^-3		@tparam U unit type to apply the prefix to.
1453 	template<class U> using centi	= typename units::detail::prefix<std::centi,U>::type;			///< Represents the type of `class U` with the metric 'centi' prefix appended.	@details E.g. centi<meters> represents meters*10^-2		@tparam U unit type to apply the prefix to.
1454 	template<class U> using deci	= typename units::detail::prefix<std::deci,	U>::type;			///< Represents the type of `class U` with the metric 'deci' prefix appended.	@details E.g. deci<meters> represents meters*10^-1		@tparam U unit type to apply the prefix to.
1455 	template<class U> using deca	= typename units::detail::prefix<std::deca,	U>::type;			///< Represents the type of `class U` with the metric 'deca' prefix appended.	@details E.g. deca<meters> represents meters*10^1		@tparam U unit type to apply the prefix to.
1456 	template<class U> using hecto	= typename units::detail::prefix<std::hecto,U>::type;			///< Represents the type of `class U` with the metric 'hecto' prefix appended.	@details E.g. hecto<meters> represents meters*10^2		@tparam U unit type to apply the prefix to.
1457 	template<class U> using kilo	= typename units::detail::prefix<std::kilo,	U>::type;			///< Represents the type of `class U` with the metric 'kilo' prefix appended.	@details E.g. kilo<meters> represents meters*10^3		@tparam U unit type to apply the prefix to.
1458 	template<class U> using mega	= typename units::detail::prefix<std::mega,	U>::type;			///< Represents the type of `class U` with the metric 'mega' prefix appended.	@details E.g. mega<meters> represents meters*10^6		@tparam U unit type to apply the prefix to.
1459 	template<class U> using giga	= typename units::detail::prefix<std::giga,	U>::type;			///< Represents the type of `class U` with the metric 'giga' prefix appended.	@details E.g. giga<meters> represents meters*10^9		@tparam U unit type to apply the prefix to.
1460 	template<class U> using tera	= typename units::detail::prefix<std::tera,	U>::type;			///< Represents the type of `class U` with the metric 'tera' prefix appended.	@details E.g. tera<meters> represents meters*10^12		@tparam U unit type to apply the prefix to.
1461 	template<class U> using peta	= typename units::detail::prefix<std::peta,	U>::type;			///< Represents the type of `class U` with the metric 'peta' prefix appended.	@details E.g. peta<meters> represents meters*10^15		@tparam U unit type to apply the prefix to.
1462 	template<class U> using exa		= typename units::detail::prefix<std::exa,	U>::type;			///< Represents the type of `class U` with the metric 'exa' prefix appended.	@details E.g. exa<meters> represents meters*10^18		@tparam U unit type to apply the prefix to.
1463 	/** @} @} */
1464 
1465 	/**
1466 	 * @ingroup UnitManipulators
1467 	 * @{
1468 	 * @ingroup Binary Prefixes
1469 	 * @{
1470 	 */
1471 	template<class U> using kibi	= typename units::detail::prefix<std::ratio<1024>,					U>::type;	///< Represents the type of `class U` with the binary 'kibi' prefix appended.	@details E.g. kibi<bytes> represents bytes*2^10	@tparam U unit type to apply the prefix to.
1472 	template<class U> using mebi	= typename units::detail::prefix<std::ratio<1048576>,				U>::type;	///< Represents the type of `class U` with the binary 'mibi' prefix appended.	@details E.g. mebi<bytes> represents bytes*2^20	@tparam U unit type to apply the prefix to.
1473 	template<class U> using gibi	= typename units::detail::prefix<std::ratio<1073741824>,			U>::type;	///< Represents the type of `class U` with the binary 'gibi' prefix appended.	@details E.g. gibi<bytes> represents bytes*2^30	@tparam U unit type to apply the prefix to.
1474 	template<class U> using tebi	= typename units::detail::prefix<std::ratio<1099511627776>,			U>::type;	///< Represents the type of `class U` with the binary 'tebi' prefix appended.	@details E.g. tebi<bytes> represents bytes*2^40	@tparam U unit type to apply the prefix to.
1475 	template<class U> using pebi	= typename units::detail::prefix<std::ratio<1125899906842624>,		U>::type;	///< Represents the type of `class U` with the binary 'pebi' prefix appended.	@details E.g. pebi<bytes> represents bytes*2^50	@tparam U unit type to apply the prefix to.
1476 	template<class U> using exbi	= typename units::detail::prefix<std::ratio<1152921504606846976>,	U>::type;	///< Represents the type of `class U` with the binary 'exbi' prefix appended.	@details E.g. exbi<bytes> represents bytes*2^60	@tparam U unit type to apply the prefix to.
1477 	/** @} @} */
1478 
1479 	//------------------------------
1480 	//	CONVERSION TRAITS
1481 	//------------------------------
1482 
1483 	namespace traits
1484 	{
1485 		/**
1486 		 * @ingroup		TypeTraits
1487 		 * @brief		Trait which checks whether two units can be converted to each other
1488 		 * @details		Inherits from `std::true_type` or `std::false_type`. Use `is_convertible_unit<U1, U2>::value` to test
1489 		 *				whether `class U1` is convertible to `class U2`. Note: convertible has both the semantic meaning,
1490 		 *				(i.e. meters can be converted to feet), and the c++ meaning of conversion (type meters can be
1491 		 *				converted to type feet). Conversion is always symmetric, so if U1 is convertible to U2, then
1492 		 *				U2 will be convertible to U1.
1493 		 * @tparam		U1 Unit to convert from.
1494 		 * @tparam		U2 Unit to convert to.
1495 		 * @sa			is_convertible_unit_t
1496 		 */
1497 		template<class U1, class U2>
1498 		struct is_convertible_unit : std::is_same <traits::base_unit_of<typename units::traits::unit_traits<U1>::base_unit_type>,
1499 			base_unit_of<typename units::traits::unit_traits<U2>::base_unit_type >> {};
1500 	}
1501 
1502 	//------------------------------
1503 	//	CONVERSION FUNCTION
1504 	//------------------------------
1505 
1506 	/** @cond */	// DOXYGEN IGNORE
1507 	namespace detail
1508 	{
pow(UNIT_LIB_DEFAULT_TYPE x,unsigned long long y)1509 		constexpr inline UNIT_LIB_DEFAULT_TYPE pow(UNIT_LIB_DEFAULT_TYPE x, unsigned long long y)
1510 		{
1511 			return y == 0 ? 1.0 : x * pow(x, y - 1);
1512 		}
1513 
abs(UNIT_LIB_DEFAULT_TYPE x)1514 		constexpr inline UNIT_LIB_DEFAULT_TYPE abs(UNIT_LIB_DEFAULT_TYPE x)
1515 		{
1516 			return x < 0 ? -x : x;
1517 		}
1518 
1519 		/// convert dispatch for units which are both the same
1520 		template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
convert(const T & value,std::true_type,std::false_type,std::false_type)1521 		static inline constexpr T convert(const T& value, std::true_type, std::false_type, std::false_type) noexcept
1522 		{
1523 			return value;
1524 		}
1525 
1526 		/// convert dispatch for units which are both the same
1527 		template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
convert(const T & value,std::true_type,std::false_type,std::true_type)1528 		static inline constexpr T convert(const T& value, std::true_type, std::false_type, std::true_type) noexcept
1529 		{
1530 			return value;
1531 		}
1532 
1533 		/// convert dispatch for units which are both the same
1534 		template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
convert(const T & value,std::true_type,std::true_type,std::false_type)1535 		static inline constexpr T convert(const T& value, std::true_type, std::true_type, std::false_type) noexcept
1536 		{
1537 			return value;
1538 		}
1539 
1540 		/// convert dispatch for units which are both the same
1541 		template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
convert(const T & value,std::true_type,std::true_type,std::true_type)1542 		static inline constexpr T convert(const T& value, std::true_type, std::true_type, std::true_type) noexcept
1543 		{
1544 			return value;
1545 		}
1546 
1547 		/// convert dispatch for units of different types w/ no translation and no PI
1548 		template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
convert(const T & value,std::false_type,std::false_type,std::false_type)1549 		static inline constexpr T convert(const T& value, std::false_type, std::false_type, std::false_type) noexcept
1550 		{
1551 			return ((value * Ratio::num) / Ratio::den);
1552 		}
1553 
1554 		/// convert dispatch for units of different types w/ no translation, but has PI in numerator
1555 		// constepxr with PI in numerator
1556 		template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
1557 		static inline constexpr
1558 		std::enable_if_t<(PiRatio::num / PiRatio::den >= 1 && PiRatio::num % PiRatio::den == 0), T>
convert(const T & value,std::false_type,std::true_type,std::false_type)1559 		convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept
1560 		{
1561 			return ((value * pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den) * Ratio::num) / Ratio::den);
1562 		}
1563 
1564 		/// convert dispatch for units of different types w/ no translation, but has PI in denominator
1565 		// constexpr with PI in denominator
1566 		template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
1567 		static inline constexpr
1568 		std::enable_if_t<(PiRatio::num / PiRatio::den <= -1 && PiRatio::num % PiRatio::den == 0), T>
convert(const T & value,std::false_type,std::true_type,std::false_type)1569  		convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept
1570  		{
1571  			return (value * Ratio::num) / (Ratio::den * pow(constants::detail::PI_VAL, -PiRatio::num / PiRatio::den));
1572  		}
1573 
1574 		/// convert dispatch for units of different types w/ no translation, but has PI in numerator
1575 		// Not constexpr - uses std::pow
1576 		template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
1577 		static inline // sorry, this can't be constexpr!
1578 		std::enable_if_t<(PiRatio::num / PiRatio::den < 1 && PiRatio::num / PiRatio::den > -1), T>
convert(const T & value,std::false_type,std::true_type,std::false_type)1579 		convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept
1580 		{
1581 			return ((value * std::pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den)  * Ratio::num) / Ratio::den);
1582 		}
1583 
1584 		/// convert dispatch for units of different types with a translation, but no PI
1585 		template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
convert(const T & value,std::false_type,std::false_type,std::true_type)1586 		static inline constexpr T convert(const T& value, std::false_type, std::false_type, std::true_type) noexcept
1587 		{
1588 			return ((value * Ratio::num) / Ratio::den) + (static_cast<UNIT_LIB_DEFAULT_TYPE>(Translation::num) / Translation::den);
1589 		}
1590 
1591 		/// convert dispatch for units of different types with a translation AND PI
1592 		template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
convert(const T & value,const std::false_type,const std::true_type,const std::true_type)1593 		static inline constexpr T convert(const T& value, const std::false_type, const std::true_type, const std::true_type) noexcept
1594 		{
1595 			return ((value * std::pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den) * Ratio::num) / Ratio::den) + (static_cast<UNIT_LIB_DEFAULT_TYPE>(Translation::num) / Translation::den);
1596 		}
1597 	}
1598 	/** @endcond */	// END DOXYGEN IGNORE
1599 
1600 	/**
1601 	 * @ingroup		Conversion
1602 	 * @brief		converts a <i>value</i> from one type to another.
1603 	 * @details		Converts a <i>value</i> of a built-in arithmetic type to another unit. This does not change
1604 	 *				the type of <i>value</i>, only what it contains. E.g. @code double result = convert<length::meters, length::feet>(1.0);	// result == 3.28084 @endcode
1605 	 * @sa			unit_t	for implicit conversion of unit containers.
1606 	 * @tparam		UnitFrom unit tag to convert <i>value</i> from. Must be a `unit` type (i.e. is_unit<UnitFrom>::value == true),
1607 	 *				and must be convertible to `UnitTo` (i.e. is_convertible_unit<UnitFrom, UnitTo>::value == true).
1608 	 * @tparam		UnitTo unit tag to convert <i>value</i> to. Must be a `unit` type (i.e. is_unit<UnitTo>::value == true),
1609 	 *				and must be convertible from `UnitFrom` (i.e. is_convertible_unit<UnitFrom, UnitTo>::value == true).
1610 	 * @tparam		T type of <i>value</i>. It is inferred from <i>value</i>, and is expected to be a built-in arithmetic type.
1611 	 * @param[in]	value Arithmetic value to convert from `UnitFrom` to `UnitTo`. The value should represent
1612 	 *				a quantity in units of `UnitFrom`.
1613 	 * @returns		value, converted from units of `UnitFrom` to `UnitTo`.
1614 	 */
1615 	template<class UnitFrom, class UnitTo, typename T = UNIT_LIB_DEFAULT_TYPE>
convert(const T & value)1616 	static inline constexpr T convert(const T& value) noexcept
1617 	{
1618 		static_assert(traits::is_unit<UnitFrom>::value, "Template parameter `UnitFrom` must be a `unit` type.");
1619 		static_assert(traits::is_unit<UnitTo>::value, "Template parameter `UnitTo` must be a `unit` type.");
1620 		static_assert(traits::is_convertible_unit<UnitFrom, UnitTo>::value, "Units are not compatible.");
1621 
1622 		using Ratio = std::ratio_divide<typename UnitFrom::conversion_ratio, typename UnitTo::conversion_ratio>;
1623 		using PiRatio = std::ratio_subtract<typename UnitFrom::pi_exponent_ratio, typename UnitTo::pi_exponent_ratio>;
1624 		using Translation = std::ratio_divide<std::ratio_subtract<typename UnitFrom::translation_ratio, typename UnitTo::translation_ratio>, typename UnitTo::conversion_ratio>;
1625 
1626 		using isSame = typename std::is_same<std::decay_t<UnitFrom>, std::decay_t<UnitTo>>::type;
1627 		using piRequired = std::integral_constant<bool, !(std::is_same<std::ratio<0>, PiRatio>::value)>;
1628 		using translationRequired = std::integral_constant<bool, !(std::is_same<std::ratio<0>, Translation>::value)>;
1629 
1630 		return units::detail::convert<UnitFrom, UnitTo, Ratio, PiRatio, Translation, T>
1631 			(value, isSame{}, piRequired{}, translationRequired{});
1632 	}
1633 
1634 	//----------------------------------
1635 	//	NON-LINEAR SCALE TRAITS
1636 	//----------------------------------
1637 
1638 	/** @cond */	// DOXYGEN IGNORE
1639 	namespace traits
1640 	{
1641 		namespace detail
1642 		{
1643 			/**
1644 			* @brief		implementation of has_operator_parenthesis
1645 			* @details		checks that operator() returns the same type as `Ret`
1646 			*/
1647 			template<class T, class Ret>
1648 			struct has_operator_parenthesis_impl
1649 			{
1650 				template<class U>
testunits::traits::detail::has_operator_parenthesis_impl1651 				static constexpr auto test(U*) -> decltype(std::declval<U>()()) { return decltype(std::declval<U>()()){}; }
1652 				template<typename>
testunits::traits::detail::has_operator_parenthesis_impl1653 				static constexpr std::false_type test(...) { return std::false_type{}; }
1654 
1655 				using type = typename std::is_same<Ret, decltype(test<T>(0))>::type;
1656 			};
1657 		}
1658 
1659 		/**
1660 		 * @brief		checks that `class T` has an `operator()` member which returns `Ret`
1661 		 * @details		used as part of the linear_scale concept.
1662 		 */
1663 		template<class T, class Ret>
1664 		struct has_operator_parenthesis : traits::detail::has_operator_parenthesis_impl<T, Ret>::type {};
1665 	}
1666 
1667 	namespace traits
1668 	{
1669 		namespace detail
1670 		{
1671 			/**
1672 			* @brief		implementation of has_value_member
1673 			* @details		checks for a member named `m_member` with type `Ret`
1674 			*/
1675 			template<class T, class Ret>
1676 			struct has_value_member_impl
1677 			{
1678 				template<class U>
testunits::traits::detail::has_value_member_impl1679 				static constexpr auto test(U* p) -> decltype(p->m_value) { return p->m_value; }
1680 				template<typename>
testunits::traits::detail::has_value_member_impl1681 				static constexpr auto test(...)->std::false_type { return std::false_type{}; }
1682 
1683 				using type = typename std::is_same<std::decay_t<Ret>, std::decay_t<decltype(test<T>(0))>>::type;
1684 			};
1685 		}
1686 
1687 		/**
1688 		 * @brief		checks for a member named `m_member` with type `Ret`
1689 		 * @details		used as part of the linear_scale concept checker.
1690 		 */
1691 		template<class T, class Ret>
1692 		struct has_value_member : traits::detail::has_value_member_impl<T, Ret>::type {};
1693 	}
1694 	/** @endcond */	// END DOXYGEN IGNORE
1695 
1696 	namespace traits
1697 	{
1698 		/**
1699 		 * @ingroup		TypeTraits
1700 		 * @brief		Trait which tests that `class T` meets the requirements for a non-linear scale
1701 		 * @details		A non-linear scale must:
1702 		 *				- be default constructible
1703 		 *				- have an `operator()` member which returns the non-linear value stored in the scale
1704 		 *				- have an accessible `m_value` member type which stores the linearized value in the scale.
1705 		 *
1706 		 *				Linear/nonlinear scales are used by `units::unit` to store values and scale them
1707 		 *				if they represent things like dB.
1708 		 */
1709 		template<class T, class Ret>
1710 		struct is_nonlinear_scale : std::integral_constant<bool,
1711 			std::is_default_constructible<T>::value &&
1712 			has_operator_parenthesis<T, Ret>::value &&
1713 			has_value_member<T, Ret>::value &&
1714 			std::is_trivial<T>::value>
1715 		{};
1716 	}
1717 
1718 	//------------------------------
1719 	//	UNIT_T TYPE TRAITS
1720 	//------------------------------
1721 
1722 	namespace traits
1723 	{
1724 #ifdef FOR_DOXYGEN_PURPOSOES_ONLY
1725 		/**
1726 		* @ingroup		TypeTraits
1727 		* @brief		Trait for accessing the publically defined types of `units::unit_t`
1728 		* @details		The units library determines certain properties of the unit_t types passed to them
1729 		*				and what they represent by using the members of the corresponding unit_t_traits instantiation.
1730 		*/
1731 		template<typename T>
1732 		struct unit_t_traits
1733 		{
1734 			typedef typename T::non_linear_scale_type non_linear_scale_type;	///< Type of the unit_t non_linear_scale (e.g. linear_scale, decibel_scale). This property is used to enable the proper linear or logarithmic arithmetic functions.
1735 			typedef typename T::underlying_type underlying_type;				///< Underlying storage type of the `unit_t`, e.g. `double`.
1736 			typedef typename T::value_type value_type;							///< Synonym for underlying type. May be removed in future versions. Prefer underlying_type.
1737 			typedef typename T::unit_type unit_type;							///< Type of unit the `unit_t` represents, e.g. `meters`
1738 		};
1739 #endif
1740 
1741 		/** @cond */	// DOXYGEN IGNORE
1742 		/**
1743 		 * @brief		unit_t_traits specialization for things which are not unit_t
1744 		 * @details
1745 		 */
1746 		template<typename T, typename = void>
1747 		struct unit_t_traits
1748 		{
1749 			typedef void non_linear_scale_type;
1750 			typedef void underlying_type;
1751 			typedef void value_type;
1752 			typedef void unit_type;
1753 		};
1754 
1755 		/**
1756 		 * @ingroup		TypeTraits
1757 		 * @brief		Trait for accessing the publically defined types of `units::unit_t`
1758 		 * @details
1759 		 */
1760 		template<typename T>
1761 		struct unit_t_traits <T, typename void_t<
1762 			typename T::non_linear_scale_type,
1763 			typename T::underlying_type,
1764 			typename T::value_type,
1765 			typename T::unit_type>::type>
1766 		{
1767 			typedef typename T::non_linear_scale_type non_linear_scale_type;
1768 			typedef typename T::underlying_type underlying_type;
1769 			typedef typename T::value_type value_type;
1770 			typedef typename T::unit_type unit_type;
1771 		};
1772 		/** @endcond */	// END DOXYGEN IGNORE
1773 	}
1774 
1775 	namespace traits
1776 	{
1777 		/**
1778 		 * @ingroup		TypeTraits
1779 		 * @brief		Trait which tests whether two container types derived from `unit_t` are convertible to each other
1780 		 * @details		Inherits from `std::true_type` or `std::false_type`. Use `is_convertible_unit_t<U1, U2>::value` to test
1781 		 *				whether `class U1` is convertible to `class U2`. Note: convertible has both the semantic meaning,
1782 		 *				(i.e. meters can be converted to feet), and the c++ meaning of conversion (type meters can be
1783 		 *				converted to type feet). Conversion is always symmetric, so if U1 is convertible to U2, then
1784 		 *				U2 will be convertible to U1.
1785 		 * @tparam		U1 Unit to convert from.
1786 		 * @tparam		U2 Unit to convert to.
1787 		 * @sa			is_convertible_unit
1788 		 */
1789 		template<class U1, class U2>
1790 		struct is_convertible_unit_t : std::integral_constant<bool,
1791 			is_convertible_unit<typename units::traits::unit_t_traits<U1>::unit_type, typename units::traits::unit_t_traits<U2>::unit_type>::value>
1792 		{};
1793 	}
1794 
1795 	//----------------------------------
1796 	//	UNIT TYPE
1797 	//----------------------------------
1798 
1799 	/** @cond */	// DOXYGEN IGNORE
1800 	// forward declaration
1801 	template<typename T> struct linear_scale;
1802 	template<typename T> struct decibel_scale;
1803 
1804 	namespace detail
1805 	{
1806 		/**
1807 		* @brief		helper type to identify units.
1808 		* @details		A non-templated base class for `unit` which enables RTTI testing.
1809 		*/
1810 		struct _unit_t {};
1811 	}
1812 	/** @endcond */	// END DOXYGEN IGNORE
1813 
1814 	namespace traits
1815 	{
1816 		// forward declaration
1817 		#if !defined(_MSC_VER) || _MSC_VER > 1800 // bug in VS2013 prevents this from working
1818 		template<typename... T> struct is_dimensionless_unit;
1819 		#else
1820 		template<typename T1, typename T2 = T1, typename T3 = T1> struct is_dimensionless_unit;
1821 		#endif
1822 
1823 		/**
1824 		 * @ingroup		TypeTraits
1825 		 * @brief		Traits which tests if a class is a `unit`
1826 		 * @details		Inherits from `std::true_type` or `std::false_type`. Use `is_unit<T>::value` to test
1827 		 *				whether `class T` implements a `unit`.
1828 		 */
1829 		template<class T>
1830 		struct is_unit_t : std::is_base_of<units::detail::_unit_t, T>::type {};
1831 	}
1832 
1833 	/**
1834 	 * @ingroup		UnitContainers
1835 	 * @brief		Container for values which represent quantities of a given unit.
1836 	 * @details		Stores a value which represents a quantity in the given units. Unit containers
1837 	 *				(except scalar values) are *not* convertible to built-in c++ types, in order to
1838 	 *				provide type safety in dimensional analysis. Unit containers *are* implicitly
1839 	 *				convertible to other compatible unit container types. Unit containers support
1840 	 *				various types of arithmetic operations, depending on their scale type.
1841 	 *
1842 	 *				The value of a `unit_t` can only be changed on construction, or by assignment
1843 	 *				from another `unit_t` type. If necessary, the underlying value can be accessed
1844 	 *				using `operator()`: @code
1845 	 *				meter_t m(5.0);
1846 	 *				double val = m(); // val == 5.0	@endcode.
1847 	 * @tparam		Units unit tag for which type of units the `unit_t` represents (e.g. meters)
1848 	 * @tparam		T underlying type of the storage. Defaults to double.
1849 	 * @tparam		NonLinearScale optional scale class for the units. Defaults to linear (i.e. does
1850 	 *				not scale the unit value). Examples of non-linear scales could be logarithmic,
1851 	 *				decibel, or richter scales. Non-linear scales must adhere to the non-linear-scale
1852 	 *				concept, i.e. `is_nonlinear_scale<...>::value` must be `true`.
1853 	 * @sa
1854 	 *				- \ref lengthContainers "length unit containers"
1855 	 *				- \ref massContainers "mass unit containers"
1856 	 *				- \ref timeContainers "time unit containers"
1857 	 *				- \ref angleContainers "angle unit containers"
1858 	 *				- \ref currentContainers "current unit containers"
1859 	 *				- \ref temperatureContainers "temperature unit containers"
1860 	 *				- \ref substanceContainers "substance unit containers"
1861 	 *				- \ref luminousIntensityContainers "luminous intensity unit containers"
1862 	 *				- \ref solidAngleContainers "solid angle unit containers"
1863 	 *				- \ref frequencyContainers "frequency unit containers"
1864 	 *				- \ref velocityContainers "velocity unit containers"
1865 	 *				- \ref angularVelocityContainers "angular velocity unit containers"
1866 	 *				- \ref accelerationContainers "acceleration unit containers"
1867 	 *				- \ref forceContainers "force unit containers"
1868 	 *				- \ref pressureContainers "pressure unit containers"
1869 	 *				- \ref chargeContainers "charge unit containers"
1870 	 *				- \ref energyContainers "energy unit containers"
1871 	 *				- \ref powerContainers "power unit containers"
1872 	 *				- \ref voltageContainers "voltage unit containers"
1873 	 *				- \ref capacitanceContainers "capacitance unit containers"
1874 	 *				- \ref impedanceContainers "impedance unit containers"
1875 	 *				- \ref magneticFluxContainers "magnetic flux unit containers"
1876 	 *				- \ref magneticFieldStrengthContainers "magnetic field strength unit containers"
1877 	 *				- \ref inductanceContainers "inductance unit containers"
1878 	 *				- \ref luminousFluxContainers "luminous flux unit containers"
1879 	 *				- \ref illuminanceContainers "illuminance unit containers"
1880 	 *				- \ref radiationContainers "radiation unit containers"
1881 	 *				- \ref torqueContainers "torque unit containers"
1882 	 *				- \ref areaContainers "area unit containers"
1883 	 *				- \ref volumeContainers "volume unit containers"
1884 	 *				- \ref densityContainers "density unit containers"
1885 	 *				- \ref concentrationContainers "concentration unit containers"
1886 	 *				- \ref constantContainers "constant unit containers"
1887 	 */
1888 	template<class Units, typename T = UNIT_LIB_DEFAULT_TYPE, template<typename> class NonLinearScale = linear_scale>
1889 	class unit_t : public NonLinearScale<T>, units::detail::_unit_t
1890 	{
1891 		static_assert(traits::is_unit<Units>::value, "Template parameter `Units` must be a unit tag. Check that you aren't using a unit type (_t).");
1892 		static_assert(traits::is_nonlinear_scale<NonLinearScale<T>, T>::value, "Template parameter `NonLinearScale` does not conform to the `is_nonlinear_scale` concept.");
1893 
1894 	protected:
1895 
1896 		using nls = NonLinearScale<T>;
1897 		using nls::m_value;
1898 
1899 	public:
1900 
1901 		typedef NonLinearScale<T> non_linear_scale_type;											///< Type of the non-linear scale of the unit_t (e.g. linear_scale)
1902 		typedef T underlying_type;																	///< Type of the underlying storage of the unit_t (e.g. double)
1903 		typedef T value_type;																		///< Synonym for underlying type. May be removed in future versions. Prefer underlying_type.
1904 		typedef Units unit_type;																	///< Type of `unit` the `unit_t` represents (e.g. meters)
1905 
1906 		/**
1907 		 * @ingroup		Constructors
1908 		 * @brief		default constructor.
1909 		 */
1910 		constexpr unit_t() = default;
1911 
1912 		/**
1913 		 * @brief		constructor
1914 		 * @details		constructs a new unit_t using the non-linear scale's constructor.
1915 		 * @param[in]	value	unit value magnitude.
1916 		 * @param[in]	args	additional constructor arguments are forwarded to the non-linear scale constructor. Which
1917 		 *						args are required depends on which scale is used. For the default (linear) scale,
1918 		 *						no additional args are necessary.
1919 		 */
1920 		template<class... Args>
unit_t(const T value,const Args &...args)1921 		inline explicit constexpr unit_t(const T value, const Args&... args) noexcept : nls(value, args...)
1922 		{
1923 
1924 		}
1925 
1926 		/**
1927 		 * @brief		constructor
1928 		 * @details		enable implicit conversions from T types ONLY for linear scalar units
1929 		 * @param[in]	value value of the unit_t
1930 		 */
1931 		template<class Ty, class = typename std::enable_if<traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value>::type>
unit_t(const Ty value)1932 		inline constexpr unit_t(const Ty value) noexcept : nls(value)
1933 		{
1934 
1935 		}
1936 
1937 		/**
1938 		 * @brief		chrono constructor
1939 		 * @details		enable implicit conversions from std::chrono::duration types ONLY for time units
1940 		 * @param[in]	value value of the unit_t
1941 		 */
1942 		template<class Rep, class Period, class = std::enable_if_t<std::is_arithmetic<Rep>::value && traits::is_ratio<Period>::value>>
unit_t(const std::chrono::duration<Rep,Period> & value)1943 		inline constexpr unit_t(const std::chrono::duration<Rep, Period>& value) noexcept :
1944 		nls(units::convert<unit<std::ratio<1,1000000000>, category::time_unit>, Units>(static_cast<T>(std::chrono::duration_cast<std::chrono::nanoseconds>(value).count())))
1945 		{
1946 
1947 		}
1948 
1949 		/**
1950 		 * @brief		copy constructor (converting)
1951 		 * @details		performs implicit unit conversions if required.
1952 		 * @param[in]	rhs unit to copy.
1953 		 */
1954 		template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
unit_t(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs)1955 		inline constexpr unit_t(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) noexcept :
1956 		nls(units::convert<UnitsRhs, Units, T>(rhs.m_value), std::true_type() /*store linear value*/)
1957 		{
1958 
1959 		}
1960 
1961 		/**
1962 		 * @brief		assignment
1963 		 * @details		performs implicit unit conversions if required
1964 		 * @param[in]	rhs unit to copy.
1965 		 */
1966 		template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
operator =(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs)1967 		inline unit_t& operator=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) noexcept
1968 		{
1969 			nls::m_value = units::convert<UnitsRhs, Units, T>(rhs.m_value);
1970 			return *this;
1971 		}
1972 
1973 		/**
1974 		* @brief		assignment
1975 		* @details		performs implicit conversions from built-in types ONLY for scalar units
1976 		* @param[in]	rhs value to copy.
1977 		*/
1978 		template<class Ty, class = std::enable_if_t<traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value>>
operator =(const Ty & rhs)1979 		inline unit_t& operator=(const Ty& rhs) noexcept
1980 		{
1981 			nls::m_value = rhs;
1982 			return *this;
1983 		}
1984 
1985 		/**
1986 		 * @brief		less-than
1987 		 * @details		compares the linearized value of two units. Performs unit conversions if necessary.
1988 		 * @param[in]	rhs right-hand side unit for the comparison
1989 		 * @returns		true IFF the value of `this` is less than the value of `rhs`
1990 		 */
1991 		template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
operator <(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs) const1992 		inline constexpr bool operator<(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
1993 		{
1994 			return (nls::m_value < units::convert<UnitsRhs, Units>(rhs.m_value));
1995 		}
1996 
1997 		/**
1998 		 * @brief		less-than or equal
1999 		 * @details		compares the linearized value of two units. Performs unit conversions if necessary.
2000 		 * @param[in]	rhs right-hand side unit for the comparison
2001 		 * @returns		true IFF the value of `this` is less than or equal to the value of `rhs`
2002 		 */
2003 		template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
operator <=(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs) const2004 		inline constexpr bool operator<=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
2005 		{
2006 			return (nls::m_value <= units::convert<UnitsRhs, Units>(rhs.m_value));
2007 		}
2008 
2009 		/**
2010 		 * @brief		greater-than
2011 		 * @details		compares the linearized value of two units. Performs unit conversions if necessary.
2012 		 * @param[in]	rhs right-hand side unit for the comparison
2013 		 * @returns		true IFF the value of `this` is greater than the value of `rhs`
2014 		 */
2015 		template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
operator >(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs) const2016 		inline constexpr bool operator>(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
2017 		{
2018 			return (nls::m_value > units::convert<UnitsRhs, Units>(rhs.m_value));
2019 		}
2020 
2021 		/**
2022 		 * @brief		greater-than or equal
2023 		 * @details		compares the linearized value of two units. Performs unit conversions if necessary.
2024 		 * @param[in]	rhs right-hand side unit for the comparison
2025 		 * @returns		true IFF the value of `this` is greater than or equal to the value of `rhs`
2026 		 */
2027 		template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
operator >=(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs) const2028 		inline constexpr bool operator>=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
2029 		{
2030 			return (nls::m_value >= units::convert<UnitsRhs, Units>(rhs.m_value));
2031 		}
2032 
2033 		/**
2034 		 * @brief		equality
2035 		 * @details		compares the linearized value of two units. Performs unit conversions if necessary.
2036 		 * @param[in]	rhs right-hand side unit for the comparison
2037 		 * @returns		true IFF the value of `this` exactly equal to the value of rhs.
2038 		 * @note		This may not be suitable for all applications when the underlying_type of unit_t is a double.
2039 		 */
2040 		template<class UnitsRhs, typename Ty, template<typename> class NlsRhs, std::enable_if_t<std::is_floating_point<T>::value || std::is_floating_point<Ty>::value, int> = 0>
operator ==(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs) const2041 		inline constexpr bool operator==(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
2042 		{
2043 			return detail::abs(nls::m_value - units::convert<UnitsRhs, Units>(rhs.m_value)) < std::numeric_limits<T>::epsilon() *
2044 				detail::abs(nls::m_value + units::convert<UnitsRhs, Units>(rhs.m_value)) ||
2045 				detail::abs(nls::m_value - units::convert<UnitsRhs, Units>(rhs.m_value)) < std::numeric_limits<T>::min();
2046 		}
2047 
2048 		template<class UnitsRhs, typename Ty, template<typename> class NlsRhs, std::enable_if_t<std::is_integral<T>::value && std::is_integral<Ty>::value, int> = 0>
operator ==(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs) const2049 		inline constexpr bool operator==(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
2050 		{
2051 			return nls::m_value == units::convert<UnitsRhs, Units>(rhs.m_value);
2052 		}
2053 
2054 		/**
2055 		 * @brief		inequality
2056 		 * @details		compares the linearized value of two units. Performs unit conversions if necessary.
2057 		 * @param[in]	rhs right-hand side unit for the comparison
2058 		 * @returns		true IFF the value of `this` is not equal to the value of rhs.
2059 		 * @note		This may not be suitable for all applications when the underlying_type of unit_t is a double.
2060 		 */
2061 		template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
operator !=(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs) const2062 		inline constexpr bool operator!=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
2063 		{
2064 			return !(*this == rhs);
2065 		}
2066 
2067 		/**
2068 		 * @brief		unit value
2069 		 * @returns		value of the unit in it's underlying, non-safe type.
2070 		 */
value() const2071 		inline constexpr underlying_type value() const noexcept
2072 		{
2073 			return static_cast<underlying_type>(*this);
2074 		}
2075 
2076 		/**
2077 		 * @brief		unit value
2078 		 * @returns		value of the unit converted to an arithmetic, non-safe type.
2079 		 */
2080 		template<typename Ty, class = std::enable_if_t<std::is_arithmetic<Ty>::value>>
to() const2081 		inline constexpr Ty to() const noexcept
2082 		{
2083 			return static_cast<Ty>(*this);
2084 		}
2085 
2086 		/**
2087 		 * @brief		linearized unit value
2088 		 * @returns		linearized value of unit which has a non-linear scale. For `unit_t` types with
2089 		 *				linear scales, this is equivalent to `value`.
2090 		 */
2091 		template<typename Ty, class = std::enable_if_t<std::is_arithmetic<Ty>::value>>
toLinearized() const2092 		inline constexpr Ty toLinearized() const noexcept
2093 		{
2094 			return static_cast<Ty>(m_value);
2095 		}
2096 
2097 		/**
2098 		 * @brief		conversion
2099 		 * @details		Converts to a different unit container. Units can be converted to other containers
2100 		 *				implicitly, but this can be used in cases where explicit notation of a conversion
2101 		 *				is beneficial, or where an r-value container is needed.
2102 		 * @tparam		U unit (not unit_t) to convert to
2103 		 * @returns		a unit container with the specified units containing the equivalent value to
2104 		 *				*this.
2105 		 */
2106 		template<class U>
convert() const2107 		inline constexpr unit_t<U> convert() const noexcept
2108 		{
2109 			static_assert(traits::is_unit<U>::value, "Template parameter `U` must be a unit type.");
2110 			return unit_t<U>(*this);
2111 		}
2112 
2113 		/**
2114 		 * @brief		implicit type conversion.
2115 		 * @details		only enabled for scalar unit types.
2116 		 */
2117 		template<class Ty, std::enable_if_t<traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value, int> = 0>
operator Ty() const2118 		inline constexpr operator Ty() const noexcept
2119 		{
2120 			// this conversion also resolves any PI exponents, by converting from a non-zero PI ratio to a zero-pi ratio.
2121 			return static_cast<Ty>(units::convert<Units, unit<std::ratio<1>, units::category::scalar_unit>>((*this)()));
2122 		}
2123 
2124 		/**
2125 		 * @brief		explicit type conversion.
2126 		 * @details		only enabled for non-dimensionless unit types.
2127 		 */
2128 		template<class Ty, std::enable_if_t<!traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value, int> = 0>
operator Ty() const2129 		inline constexpr explicit operator Ty() const noexcept
2130 		{
2131 			return static_cast<Ty>((*this)());
2132 		}
2133 
2134 		/**
2135 		 * @brief		chrono implicit type conversion.
2136 		 * @details		only enabled for time unit types.
2137 		 */
2138 		template<typename U = Units, std::enable_if_t<units::traits::is_convertible_unit<U, unit<std::ratio<1>, category::time_unit>>::value, int> = 0>
operator std::chrono::nanoseconds() const2139 		inline constexpr operator std::chrono::nanoseconds() const noexcept
2140 		{
2141 			return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::duration<double, std::nano>(units::convert<Units, unit<std::ratio<1,1000000000>, category::time_unit>>((*this)())));
2142 		}
2143 
2144 		/**
2145 		 * @brief		returns the unit name
2146 		 */
name() const2147 		inline constexpr const char* name() const noexcept
2148 		{
2149 			return units::name(*this);
2150 		}
2151 
2152 		/**
2153 		 * @brief		returns the unit abbreviation
2154 		 */
abbreviation() const2155 		inline constexpr const char* abbreviation() const noexcept
2156 		{
2157 			return units::abbreviation(*this);
2158 		}
2159 
2160 	public:
2161 
2162 		template<class U, typename Ty, template<typename> class Nlt>
2163 		friend class unit_t;
2164 	};
2165 
2166 	//------------------------------
2167 	//	UNIT_T NON-MEMBER FUNCTIONS
2168 	//------------------------------
2169 
2170 	/**
2171 	 * @ingroup		UnitContainers
2172 	 * @brief		Constructs a unit container from an arithmetic type.
2173 	 * @details		make_unit can be used to construct a unit container from an arithmetic type, as an alternative to
2174 	 *				using the explicit constructor. Unlike the explicit constructor it forces the user to explicitly
2175 	 *				specify the units.
2176 	 * @tparam		UnitType Type to construct.
2177 	 * @tparam		Ty		Arithmetic type.
2178 	 * @param[in]	value	Arithmetic value that represents a quantity in units of `UnitType`.
2179 	 */
2180 	template<class UnitType, typename T, class = std::enable_if_t<std::is_arithmetic<T>::value>>
make_unit(const T value)2181 	inline constexpr UnitType make_unit(const T value) noexcept
2182 	{
2183 		static_assert(traits::is_unit_t<UnitType>::value, "Template parameter `UnitType` must be a unit type (_t).");
2184 
2185 		return UnitType(value);
2186 	}
2187 
2188 #if !defined(UNIT_LIB_DISABLE_IOSTREAM)
2189 	template<class Units, typename T, template<typename> class NonLinearScale>
operator <<(std::ostream & os,const unit_t<Units,T,NonLinearScale> & obj)2190 	inline std::ostream& operator<<(std::ostream& os, const unit_t<Units, T, NonLinearScale>& obj) noexcept
2191 	{
2192     // change made by twhuang
2193     // we don't need the long name as defined in the original library.
2194     os << obj.value() << ' ' << units::abbreviation(obj);
2195     return os;
2196 
2197 		/*using BaseUnits = unit<std::ratio<1>, typename traits::unit_traits<Units>::base_unit_type>;
2198 		os << convert<Units, BaseUnits>(obj());
2199 
2200 
2201 
2202 		if (traits::unit_traits<Units>::base_unit_type::meter_ratio::num != 0) { os << " m"; }
2203 		if (traits::unit_traits<Units>::base_unit_type::meter_ratio::num != 0 &&
2204 			traits::unit_traits<Units>::base_unit_type::meter_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::meter_ratio::num; }
2205 		if (traits::unit_traits<Units>::base_unit_type::meter_ratio::den != 1) { os << "/"   << traits::unit_traits<Units>::base_unit_type::meter_ratio::den; }
2206 
2207 		if (traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num != 0) { os << " kg"; }
2208 		if (traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num != 0 &&
2209 			traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num; }
2210 		if (traits::unit_traits<Units>::base_unit_type::kilogram_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::kilogram_ratio::den; }
2211 
2212 		if (traits::unit_traits<Units>::base_unit_type::second_ratio::num != 0) { os << " s"; }
2213 		if (traits::unit_traits<Units>::base_unit_type::second_ratio::num != 0 &&
2214 			traits::unit_traits<Units>::base_unit_type::second_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::second_ratio::num; }
2215 		if (traits::unit_traits<Units>::base_unit_type::second_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::second_ratio::den; }
2216 
2217 		if (traits::unit_traits<Units>::base_unit_type::ampere_ratio::num != 0) { os << " A"; }
2218 		if (traits::unit_traits<Units>::base_unit_type::ampere_ratio::num != 0 &&
2219 			traits::unit_traits<Units>::base_unit_type::ampere_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::ampere_ratio::num; }
2220 		if (traits::unit_traits<Units>::base_unit_type::ampere_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::ampere_ratio::den; }
2221 
2222 		if (traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num != 0) { os << " K"; }
2223 		if (traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num != 0 &&
2224 			traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num; }
2225 		if (traits::unit_traits<Units>::base_unit_type::kelvin_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::kelvin_ratio::den; }
2226 
2227 		if (traits::unit_traits<Units>::base_unit_type::mole_ratio::num != 0) { os << " mol"; }
2228 		if (traits::unit_traits<Units>::base_unit_type::mole_ratio::num != 0 &&
2229 			traits::unit_traits<Units>::base_unit_type::mole_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::mole_ratio::num; }
2230 		if (traits::unit_traits<Units>::base_unit_type::mole_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::mole_ratio::den; }
2231 
2232 		if (traits::unit_traits<Units>::base_unit_type::candela_ratio::num != 0) { os << " cd"; }
2233 		if (traits::unit_traits<Units>::base_unit_type::candela_ratio::num != 0 &&
2234 			traits::unit_traits<Units>::base_unit_type::candela_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::candela_ratio::num; }
2235 		if (traits::unit_traits<Units>::base_unit_type::candela_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::candela_ratio::den; }
2236 
2237 		if (traits::unit_traits<Units>::base_unit_type::radian_ratio::num != 0) { os << " rad"; }
2238 		if (traits::unit_traits<Units>::base_unit_type::radian_ratio::num != 0 &&
2239 			traits::unit_traits<Units>::base_unit_type::radian_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::radian_ratio::num; }
2240 		if (traits::unit_traits<Units>::base_unit_type::radian_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::radian_ratio::den; }
2241 
2242 		if (traits::unit_traits<Units>::base_unit_type::byte_ratio::num != 0) { os << " b"; }
2243 		if (traits::unit_traits<Units>::base_unit_type::byte_ratio::num != 0 &&
2244 			traits::unit_traits<Units>::base_unit_type::byte_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::byte_ratio::num; }
2245 		if (traits::unit_traits<Units>::base_unit_type::byte_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::byte_ratio::den; }
2246 
2247 		return os;*/
2248 	}
2249 #endif
2250 
2251 	template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
operator +=(unit_t<Units,T,NonLinearScale> & lhs,const RhsType & rhs)2252 	inline unit_t<Units, T, NonLinearScale>& operator+=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
2253 	{
2254 		static_assert(traits::is_convertible_unit_t<unit_t<Units, T, NonLinearScale>, RhsType>::value ||
2255 			(traits::is_dimensionless_unit<decltype(lhs)>::value && std::is_arithmetic<RhsType>::value),
2256 			"parameters are not compatible units.");
2257 
2258 		lhs = lhs + rhs;
2259 		return lhs;
2260 	}
2261 
2262 	template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
operator -=(unit_t<Units,T,NonLinearScale> & lhs,const RhsType & rhs)2263 	inline unit_t<Units, T, NonLinearScale>& operator-=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
2264 	{
2265 		static_assert(traits::is_convertible_unit_t<unit_t<Units, T, NonLinearScale>, RhsType>::value ||
2266 			(traits::is_dimensionless_unit<decltype(lhs)>::value && std::is_arithmetic<RhsType>::value),
2267 			"parameters are not compatible units.");
2268 
2269 		lhs = lhs - rhs;
2270 		return lhs;
2271 	}
2272 
2273 	template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
operator *=(unit_t<Units,T,NonLinearScale> & lhs,const RhsType & rhs)2274 	inline unit_t<Units, T, NonLinearScale>& operator*=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
2275 	{
2276 		static_assert((traits::is_dimensionless_unit<RhsType>::value || std::is_arithmetic<RhsType>::value),
2277 			"right-hand side parameter must be dimensionless.");
2278 
2279 		lhs = lhs * rhs;
2280 		return lhs;
2281 	}
2282 
2283 	template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
operator /=(unit_t<Units,T,NonLinearScale> & lhs,const RhsType & rhs)2284 	inline unit_t<Units, T, NonLinearScale>& operator/=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
2285 	{
2286 		static_assert((traits::is_dimensionless_unit<RhsType>::value || std::is_arithmetic<RhsType>::value),
2287 			"right-hand side parameter must be dimensionless.");
2288 
2289 		lhs = lhs / rhs;
2290 		return lhs;
2291 	}
2292 
2293 	//------------------------------
2294 	//	UNIT_T UNARY OPERATORS
2295 	//------------------------------
2296 
2297 	// unary addition: +T
2298 	template<class Units, typename T, template<typename> class NonLinearScale>
operator +(const unit_t<Units,T,NonLinearScale> & u)2299 	inline unit_t<Units, T, NonLinearScale> operator+(const unit_t<Units, T, NonLinearScale>& u) noexcept
2300 	{
2301 		return u;
2302 	}
2303 
2304 	// prefix increment: ++T
2305 	template<class Units, typename T, template<typename> class NonLinearScale>
operator ++(unit_t<Units,T,NonLinearScale> & u)2306 	inline unit_t<Units, T, NonLinearScale>& operator++(unit_t<Units, T, NonLinearScale>& u) noexcept
2307 	{
2308 		u = unit_t<Units, T, NonLinearScale>(u() + 1);
2309 		return u;
2310 	}
2311 
2312 	// postfix increment: T++
2313 	template<class Units, typename T, template<typename> class NonLinearScale>
operator ++(unit_t<Units,T,NonLinearScale> & u,int)2314 	inline unit_t<Units, T, NonLinearScale> operator++(unit_t<Units, T, NonLinearScale>& u, int) noexcept
2315 	{
2316 		auto ret = u;
2317 		u = unit_t<Units, T, NonLinearScale>(u() + 1);
2318 		return ret;
2319 	}
2320 
2321 	// unary addition: -T
2322 	template<class Units, typename T, template<typename> class NonLinearScale>
operator -(const unit_t<Units,T,NonLinearScale> & u)2323 	inline unit_t<Units, T, NonLinearScale> operator-(const unit_t<Units, T, NonLinearScale>& u) noexcept
2324 	{
2325 		return unit_t<Units, T, NonLinearScale>(-u());
2326 	}
2327 
2328 	// prefix increment: --T
2329 	template<class Units, typename T, template<typename> class NonLinearScale>
operator --(unit_t<Units,T,NonLinearScale> & u)2330 	inline unit_t<Units, T, NonLinearScale>& operator--(unit_t<Units, T, NonLinearScale>& u) noexcept
2331 	{
2332 		u = unit_t<Units, T, NonLinearScale>(u() - 1);
2333 		return u;
2334 	}
2335 
2336 	// postfix increment: T--
2337 	template<class Units, typename T, template<typename> class NonLinearScale>
operator --(unit_t<Units,T,NonLinearScale> & u,int)2338 	inline unit_t<Units, T, NonLinearScale> operator--(unit_t<Units, T, NonLinearScale>& u, int) noexcept
2339 	{
2340 		auto ret = u;
2341 		u = unit_t<Units, T, NonLinearScale>(u() - 1);
2342 		return ret;
2343 	}
2344 
2345 	//------------------------------
2346 	//	UNIT_CAST
2347 	//------------------------------
2348 
2349 	/**
2350 	 * @ingroup		Conversion
2351 	 * @brief		Casts a unit container to an arithmetic type.
2352 	 * @details		unit_cast can be used to remove the strong typing from a unit class, and convert it
2353 	 *				to a built-in arithmetic type. This may be useful for compatibility with libraries
2354 	 *				and legacy code that don't support `unit_t` types. E.g
2355 	 * @code		meter_t unitVal(5);
2356 	 *  double value = units::unit_cast<double>(unitVal);	// value = 5.0
2357 	 * @endcode
2358 	 * @tparam		T		Type to cast the unit type to. Must be a built-in arithmetic type.
2359 	 * @param		value	Unit value to cast.
2360 	 * @sa			unit_t::to
2361 	 */
2362 	template<typename T, typename Units, class = std::enable_if_t<std::is_arithmetic<T>::value && traits::is_unit_t<Units>::value>>
unit_cast(const Units & value)2363 	inline constexpr T unit_cast(const Units& value) noexcept
2364 	{
2365 		return static_cast<T>(value);
2366 	}
2367 
2368 	//------------------------------
2369 	//	NON-LINEAR SCALE TRAITS
2370 	//------------------------------
2371 
2372 	// forward declaration
2373 	template<typename T> struct decibel_scale;
2374 
2375 	namespace traits
2376 	{
2377 		/**
2378 		 * @ingroup		TypeTraits
2379 		 * @brief		Trait which tests whether a type is inherited from a linear scale.
2380 		 * @details		Inherits from `std::true_type` or `std::false_type`. Use `has_linear_scale<U1 [, U2, ...]>::value` to test
2381 		 *				one or more types to see if they represent unit_t's whose scale is linear.
2382 		 * @tparam		T	one or more types to test.
2383 		 */
2384 #if !defined(_MSC_VER) || _MSC_VER > 1800	// bug in VS2013 prevents this from working
2385 		template<typename... T>
2386 		struct has_linear_scale : std::integral_constant<bool, units::all_true<std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T>::underlying_type>, T>::value...>::value > {};
2387 #else
2388 		template<typename T1, typename T2 = T1, typename T3 = T1>
2389 		struct has_linear_scale : std::integral_constant<bool,
2390 			std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T1>::underlying_type>, T1>::value &&
2391 			std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T2>::underlying_type>, T2>::value &&
2392 			std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T3>::underlying_type>, T3>::value> {};
2393 #endif
2394 
2395 		/**
2396 		 * @ingroup		TypeTraits
2397 		 * @brief		Trait which tests whether a type is inherited from a decibel scale.
2398 		 * @details		Inherits from `std::true_type` or `std::false_type`. Use `has_decibel_scale<U1 [, U2, ...]>::value` to test
2399 		 *				one or more types to see if they represent unit_t's whose scale is in decibels.
2400 		 * @tparam		T	one or more types to test.
2401 		 */
2402 #if !defined(_MSC_VER) || _MSC_VER > 1800	// bug in VS2013 prevents this from working
2403 		template<typename... T>
2404 		struct has_decibel_scale : std::integral_constant<bool,	units::all_true<std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T>::underlying_type>, T>::value...>::value> {};
2405 #else
2406 		template<typename T1, typename T2 = T1, typename T3 = T1>
2407 		struct has_decibel_scale : std::integral_constant<bool,
2408 			std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T1>::underlying_type>, T1>::value &&
2409 			std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T2>::underlying_type>, T2>::value &&
2410 			std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T2>::underlying_type>, T3>::value> {};
2411 #endif
2412 
2413 		/**
2414 		 * @ingroup		TypeTraits
2415 		 * @brief		Trait which tests whether two types has the same non-linear scale.
2416 		 * @details		Inherits from `std::true_type` or `std::false_type`. Use `is_same_scale<U1 , U2>::value` to test
2417 		 *				whether two types have the same non-linear scale.
2418 		 * @tparam		T1	left hand type.
2419 		 * @tparam		T2	right hand type
2420 		 */
2421 		template<typename T1, typename T2>
2422 		struct is_same_scale : std::integral_constant<bool,
2423 			std::is_same<typename units::traits::unit_t_traits<T1>::non_linear_scale_type, typename units::traits::unit_t_traits<T2>::non_linear_scale_type>::value>
2424 		{};
2425 	}
2426 
2427 	//----------------------------------
2428 	//	NON-LINEAR SCALES
2429 	//----------------------------------
2430 
2431 	// Non-linear transforms are used to pre and post scale units which are defined in terms of non-
2432 	// linear functions of their current value. A good example of a non-linear scale would be a
2433 	// logarithmic or decibel scale
2434 
2435 	//------------------------------
2436 	//	LINEAR SCALE
2437 	//------------------------------
2438 
2439 	/**
2440 	 * @brief		unit_t scale which is linear
2441 	 * @details		Represents units on a linear scale. This is the appropriate unit_t scale for almost
2442 	 *				all units almost all of the time.
2443 	 * @tparam		T	underlying storage type
2444 	 * @sa			unit_t
2445 	 */
2446 	template<typename T>
2447 	struct linear_scale
2448 	{
2449 		inline constexpr linear_scale() = default;													///< default constructor.
2450 		inline constexpr linear_scale(const linear_scale&) = default;
2451 		inline ~linear_scale() = default;
2452 		inline linear_scale& operator=(const linear_scale&) = default;
2453 #if defined(_MSC_VER) && (_MSC_VER > 1800)
2454 		inline constexpr linear_scale(linear_scale&&) = default;
2455 		inline linear_scale& operator=(linear_scale&&) = default;
2456 #endif
2457 		template<class... Args>
linear_scaleunits::linear_scale2458 		inline constexpr linear_scale(const T& value, Args&&...) noexcept : m_value(value) {}	///< constructor.
operator ()units::linear_scale2459 		inline constexpr T operator()() const noexcept { return m_value; }							///< returns value.
2460 
2461 		T m_value;																					///< linearized value.
2462 	};
2463 
2464 	//----------------------------------
2465 	//	SCALAR (LINEAR) UNITS
2466 	//----------------------------------
2467 
2468 	// Scalar units are the *ONLY* units implicitly convertible to/from built-in types.
2469 	namespace dimensionless
2470 	{
2471 		typedef unit<std::ratio<1>, units::category::scalar_unit> scalar;
2472 		typedef unit<std::ratio<1>, units::category::dimensionless_unit> dimensionless;
2473 
2474 		typedef unit_t<scalar> scalar_t;
2475 		typedef scalar_t dimensionless_t;
2476 	}
2477 
2478 // ignore the redeclaration of the default template parameters
2479 #if defined(_MSC_VER)
2480 #	pragma warning(push)
2481 #	pragma warning(disable : 4348)
2482 #endif
2483 	UNIT_ADD_CATEGORY_TRAIT(scalar)
2484 	UNIT_ADD_CATEGORY_TRAIT(dimensionless)
2485 #if defined(_MSC_VER)
2486 #	pragma warning(pop)
2487 #endif
2488 
2489 	//------------------------------
2490 	//	LINEAR ARITHMETIC
2491 	//------------------------------
2492 
2493 	template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<!traits::is_same_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
2494 	constexpr inline int operator+(const UnitTypeLhs& /* lhs */, const UnitTypeRhs& /* rhs */) noexcept
2495 	{
2496 		static_assert(traits::is_same_scale<UnitTypeLhs, UnitTypeRhs>::value, "Cannot add units with different linear/non-linear scales.");
2497 		return 0;
2498 	}
2499 
2500 	/// Addition operator for unit_t types with a linear_scale.
2501 	template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
operator +(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2502 	inline constexpr UnitTypeLhs operator+(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
2503 	{
2504 		using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2505 		using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2506 		return UnitTypeLhs(lhs() + convert<UnitsRhs, UnitsLhs>(rhs()));
2507 	}
2508 
2509 	/// Addition operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types.
2510 	template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
operator +(const dimensionless::scalar_t & lhs,T rhs)2511 	inline constexpr dimensionless::scalar_t operator+(const dimensionless::scalar_t& lhs, T rhs) noexcept
2512 	{
2513 		return dimensionless::scalar_t(lhs() + rhs);
2514 	}
2515 
2516 	/// Addition operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types.
2517 	template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
operator +(T lhs,const dimensionless::scalar_t & rhs)2518 	inline constexpr dimensionless::scalar_t operator+(T lhs, const dimensionless::scalar_t& rhs) noexcept
2519 	{
2520 		return dimensionless::scalar_t(lhs + rhs());
2521 	}
2522 
2523 	/// Subtraction operator for unit_t types with a linear_scale.
2524 	template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
operator -(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2525 	inline constexpr UnitTypeLhs operator-(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
2526 	{
2527 		using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2528 		using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2529 		return UnitTypeLhs(lhs() - convert<UnitsRhs, UnitsLhs>(rhs()));
2530 	}
2531 
2532 	/// Subtraction operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types.
2533 	template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
operator -(const dimensionless::scalar_t & lhs,T rhs)2534 	inline constexpr dimensionless::scalar_t operator-(const dimensionless::scalar_t& lhs, T rhs) noexcept
2535 	{
2536 		return dimensionless::scalar_t(lhs() - rhs);
2537 	}
2538 
2539 	/// Subtraction operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types.
2540 	template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
operator -(T lhs,const dimensionless::scalar_t & rhs)2541 	inline constexpr dimensionless::scalar_t operator-(T lhs, const dimensionless::scalar_t& rhs) noexcept
2542 	{
2543 		return dimensionless::scalar_t(lhs - rhs());
2544 	}
2545 
2546 	/// Multiplication type for convertible unit_t types with a linear scale. @returns the multiplied value, with the same type as left-hand side unit.
2547 	template<class UnitTypeLhs, class UnitTypeRhs,
2548 		std::enable_if_t<traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
operator *(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2549 		inline constexpr auto operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<squared<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>>>
2550 	{
2551 		using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2552 		using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2553 		return  unit_t<compound_unit<squared<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>>>
2554 			(lhs() * convert<UnitsRhs, UnitsLhs>(rhs()));
2555 	}
2556 
2557 	/// Multiplication type for non-convertible unit_t types with a linear scale. @returns the multiplied value, whose type is a compound unit of the left and right hand side values.
2558 	template<class UnitTypeLhs, class UnitTypeRhs,
2559 		std::enable_if_t<!traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
operator *(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2560 		inline constexpr auto operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type, typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
2561 	{
2562 		using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2563 		using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2564 		return unit_t<compound_unit<UnitsLhs, UnitsRhs>>
2565 			(lhs() * rhs());
2566 	}
2567 
2568 	/// Multiplication by a dimensionless unit for unit_t types with a linear scale.
2569 	template<class UnitTypeLhs, typename UnitTypeRhs,
2570 		std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value && traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
operator *(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2571 		inline constexpr UnitTypeLhs operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
2572 	{
2573 		// the cast makes sure factors of PI are handled as expected
2574 		return UnitTypeLhs(lhs() * static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
2575 	}
2576 
2577 	/// Multiplication by a dimensionless unit for unit_t types with a linear scale.
2578 	template<class UnitTypeLhs, typename UnitTypeRhs,
2579 		std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && traits::is_dimensionless_unit<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
operator *(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2580 		inline constexpr UnitTypeRhs operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
2581 	{
2582 		// the cast makes sure factors of PI are handled as expected
2583 		return UnitTypeRhs(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) * rhs());
2584 	}
2585 
2586 	/// Multiplication by a scalar for unit_t types with a linear scale.
2587 	template<class UnitTypeLhs, typename T,
2588 		std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeLhs>::value, int> = 0>
operator *(const UnitTypeLhs & lhs,T rhs)2589 		inline constexpr UnitTypeLhs operator*(const UnitTypeLhs& lhs, T rhs) noexcept
2590 	{
2591 		return UnitTypeLhs(lhs() * rhs);
2592 	}
2593 
2594 	/// Multiplication by a scalar for unit_t types with a linear scale.
2595 	template<class UnitTypeRhs, typename T,
2596 		std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeRhs>::value, int> = 0>
operator *(T lhs,const UnitTypeRhs & rhs)2597 		inline constexpr UnitTypeRhs operator*(T lhs, const UnitTypeRhs& rhs) noexcept
2598 	{
2599 		return UnitTypeRhs(lhs * rhs());
2600 	}
2601 
2602 	/// Division for convertible unit_t types with a linear scale. @returns the lhs divided by rhs value, whose type is a scalar
2603 	template<class UnitTypeLhs, class UnitTypeRhs,
2604 		std::enable_if_t<traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
operator /(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2605 		inline constexpr dimensionless::scalar_t operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
2606 	{
2607 		using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2608 		using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2609 		return dimensionless::scalar_t(lhs() / convert<UnitsRhs, UnitsLhs>(rhs()));
2610 	}
2611 
2612 	/// Division for non-convertible unit_t types with a linear scale. @returns the lhs divided by the rhs, with a compound unit type of lhs/rhs
2613 	template<class UnitTypeLhs, class UnitTypeRhs,
2614 		std::enable_if_t<!traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
operator /(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2615 		inline constexpr auto operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept ->  unit_t<compound_unit<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type, inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>>
2616 	{
2617 		using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2618 		using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2619 		return unit_t<compound_unit<UnitsLhs, inverse<UnitsRhs>>>
2620 			(lhs() / rhs());
2621 	}
2622 
2623 	/// Division by a dimensionless unit for unit_t types with a linear scale
2624 	template<class UnitTypeLhs, class UnitTypeRhs,
2625 		std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value && traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
operator /(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2626 		inline constexpr UnitTypeLhs operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
2627 	{
2628 		return UnitTypeLhs(lhs() / static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
2629 	}
2630 
2631 	/// Division of a dimensionless unit  by a unit_t type with a linear scale
2632 	template<class UnitTypeLhs, class UnitTypeRhs,
2633 		std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && traits::is_dimensionless_unit<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
operator /(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2634 		inline constexpr auto operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
2635 	{
2636 		return unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
2637 			(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) / rhs());
2638 	}
2639 
2640 	/// Division by a scalar for unit_t types with a linear scale
2641 	template<class UnitTypeLhs, typename T,
2642 		std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeLhs>::value, int> = 0>
operator /(const UnitTypeLhs & lhs,T rhs)2643 		inline constexpr UnitTypeLhs operator/(const UnitTypeLhs& lhs, T rhs) noexcept
2644 	{
2645 		return UnitTypeLhs(lhs() / rhs);
2646 	}
2647 
2648 	/// Division of a scalar  by a unit_t type with a linear scale
2649 	template<class UnitTypeRhs, typename T,
2650 		std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeRhs>::value, int> = 0>
operator /(T lhs,const UnitTypeRhs & rhs)2651 		inline constexpr auto operator/(T lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
2652 	{
2653 		using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2654 		return unit_t<inverse<UnitsRhs>>
2655 			(lhs / rhs());
2656 	}
2657 
2658 	//----------------------------------
2659 	//	SCALAR COMPARISONS
2660 	//----------------------------------
2661 
2662 	template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
operator ==(const UNIT_LIB_DEFAULT_TYPE lhs,const Units & rhs)2663 	constexpr bool operator==(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
2664 	{
2665 		return detail::abs(lhs - static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs)) < std::numeric_limits<UNIT_LIB_DEFAULT_TYPE>::epsilon() * detail::abs(lhs + static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs)) ||
2666 			detail::abs(lhs - static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs)) < std::numeric_limits<UNIT_LIB_DEFAULT_TYPE>::min();
2667 	}
2668 
2669 	template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
operator ==(const Units & lhs,const UNIT_LIB_DEFAULT_TYPE rhs)2670 	constexpr bool operator==(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
2671 	{
2672 		return detail::abs(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) - rhs) < std::numeric_limits<UNIT_LIB_DEFAULT_TYPE>::epsilon() * detail::abs(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) + rhs) ||
2673 			detail::abs(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) - rhs) < std::numeric_limits<UNIT_LIB_DEFAULT_TYPE>::min();
2674 	}
2675 
2676 	template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
operator !=(const UNIT_LIB_DEFAULT_TYPE lhs,const Units & rhs)2677 	constexpr bool operator!=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
2678 	{
2679 		return!(lhs == static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
2680 	}
2681 
2682 	template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
operator !=(const Units & lhs,const UNIT_LIB_DEFAULT_TYPE rhs)2683 	constexpr bool operator!=(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
2684 	{
2685 		return !(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) == rhs);
2686 	}
2687 
2688 	template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
operator >=(const UNIT_LIB_DEFAULT_TYPE lhs,const Units & rhs)2689 	constexpr bool operator>=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
2690 	{
2691 		return std::isgreaterequal(lhs, static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
2692 	}
2693 
2694 	template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
operator >=(const Units & lhs,const UNIT_LIB_DEFAULT_TYPE rhs)2695 	constexpr bool operator>=(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
2696 	{
2697 		return std::isgreaterequal(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs), rhs);
2698 	}
2699 
2700 	template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
operator >(const UNIT_LIB_DEFAULT_TYPE lhs,const Units & rhs)2701 	constexpr bool operator>(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
2702 	{
2703 		return lhs > static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs);
2704 	}
2705 
2706 	template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
operator >(const Units & lhs,const UNIT_LIB_DEFAULT_TYPE rhs)2707 	constexpr bool operator>(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
2708 	{
2709 		return static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) > rhs;
2710 	}
2711 
2712 	template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
operator <=(const UNIT_LIB_DEFAULT_TYPE lhs,const Units & rhs)2713 	constexpr bool operator<=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
2714 	{
2715 		return std::islessequal(lhs, static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
2716 	}
2717 
2718 	template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
operator <=(const Units & lhs,const UNIT_LIB_DEFAULT_TYPE rhs)2719 	constexpr bool operator<=(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
2720 	{
2721 		return std::islessequal(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs), rhs);
2722 	}
2723 
2724 	template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
operator <(const UNIT_LIB_DEFAULT_TYPE lhs,const Units & rhs)2725 	constexpr bool operator<(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
2726 	{
2727 		return lhs < static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs);
2728 	}
2729 
2730 	template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
operator <(const Units & lhs,const UNIT_LIB_DEFAULT_TYPE rhs)2731 	constexpr bool operator<(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
2732 	{
2733 		return static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) < rhs;
2734 	}
2735 
2736 	//----------------------------------
2737 	//	POW
2738 	//----------------------------------
2739 
2740 	/** @cond */	// DOXYGEN IGNORE
2741 	namespace detail
2742 	{
2743 		/// recursive exponential implementation
2744 		template <int N, class U> struct power_of_unit
2745 		{
2746 			typedef typename units::detail::unit_multiply<U, typename power_of_unit<N - 1, U>::type> type;
2747 		};
2748 
2749 		/// End recursion
2750 		template <class U> struct power_of_unit<1, U>
2751 		{
2752 			typedef U type;
2753 		};
2754 	}
2755 	/** @endcond */	// END DOXYGEN IGNORE
2756 
2757 	namespace math
2758 	{
2759 		/**
2760 		 * @brief		computes the value of <i>value</i> raised to the <i>power</i>
2761 		 * @details		Only implemented for linear_scale units. <i>Power</i> must be known at compile time, so the resulting unit type can be deduced.
2762 		 * @tparam		power exponential power to raise <i>value</i> by.
2763 		 * @param[in]	value `unit_t` derived type to raise to the given <i>power</i>
2764 		 * @returns		new unit_t, raised to the given exponent
2765 		 */
2766 		template<int power, class UnitType, class = typename std::enable_if<traits::has_linear_scale<UnitType>::value, int>>
pow(const UnitType & value)2767 		inline auto pow(const UnitType& value) noexcept -> unit_t<typename units::detail::power_of_unit<power, typename units::traits::unit_t_traits<UnitType>::unit_type>::type, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
2768 		{
2769 			return unit_t<typename units::detail::power_of_unit<power, typename units::traits::unit_t_traits<UnitType>::unit_type>::type, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
2770 				(std::pow(value(), power));
2771 		}
2772 
2773 		/**
2774 		 * @brief		computes the value of <i>value</i> raised to the <i>power</i> as a constexpr
2775 		 * @details		Only implemented for linear_scale units. <i>Power</i> must be known at compile time, so the resulting unit type can be deduced.
2776 		 *				Additionally, the power must be <i>a positive, integral, value</i>.
2777 		 * @tparam		power exponential power to raise <i>value</i> by.
2778 		 * @param[in]	value `unit_t` derived type to raise to the given <i>power</i>
2779 		 * @returns		new unit_t, raised to the given exponent
2780 		 */
2781 		template<int power, class UnitType, class = typename std::enable_if<traits::has_linear_scale<UnitType>::value, int>>
cpow(const UnitType & value)2782 		inline constexpr auto cpow(const UnitType& value) noexcept -> unit_t<typename units::detail::power_of_unit<power, typename units::traits::unit_t_traits<UnitType>::unit_type>::type, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
2783 		{
2784 			static_assert(power >= 0, "cpow cannot accept negative numbers. Try units::math::pow instead.");
2785 			return unit_t<typename units::detail::power_of_unit<power, typename units::traits::unit_t_traits<UnitType>::unit_type>::type, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
2786 				(detail::pow(value(), power));
2787 		}
2788 	}
2789 
2790 	//------------------------------
2791 	//	DECIBEL SCALE
2792 	//------------------------------
2793 
2794 	/**
2795 	* @brief		unit_t scale for representing decibel values.
2796 	* @details		internally stores linearized values. `operator()` returns the value in dB.
2797 	* @tparam		T	underlying storage type
2798 	* @sa			unit_t
2799 	*/
2800 	template<typename T>
2801 	struct decibel_scale
2802 	{
2803 		inline constexpr decibel_scale() = default;
2804 		inline constexpr decibel_scale(const decibel_scale&) = default;
2805 		inline ~decibel_scale() = default;
2806 		inline decibel_scale& operator=(const decibel_scale&) = default;
2807 #if defined(_MSC_VER) && (_MSC_VER > 1800)
2808 		inline constexpr decibel_scale(decibel_scale&&) = default;
2809 		inline decibel_scale& operator=(decibel_scale&&) = default;
2810 #endif
decibel_scaleunits::decibel_scale2811 		inline constexpr decibel_scale(const T value) noexcept : m_value(std::pow(10, value / 10)) {}
2812 		template<class... Args>
decibel_scaleunits::decibel_scale2813 		inline constexpr decibel_scale(const T value, std::true_type, Args&&...) noexcept : m_value(value) {}
operator ()units::decibel_scale2814 		inline constexpr T operator()() const noexcept { return 10 * std::log10(m_value); }
2815 
2816 		T m_value;	///< linearized value
2817 	};
2818 
2819 	//------------------------------
2820 	//	SCALAR (DECIBEL) UNITS
2821 	//------------------------------
2822 
2823 	/**
2824 	 * @brief		namespace for unit types and containers for units that have no dimension (scalar units)
2825 	 * @sa			See unit_t for more information on unit type containers.
2826 	 */
2827 	namespace dimensionless
2828 	{
2829 		typedef unit_t<scalar, UNIT_LIB_DEFAULT_TYPE, decibel_scale> dB_t;
2830 #if !defined(UNIT_LIB_DISABLE_IOSTREAM)
operator <<(std::ostream & os,const dB_t & obj)2831 		inline std::ostream& operator<<(std::ostream& os, const dB_t& obj) { os << obj() << " dB"; return os; }
2832 #endif
2833 		typedef dB_t dBi_t;
2834 	}
2835 
2836 	//------------------------------
2837 	//	DECIBEL ARITHMETIC
2838 	//------------------------------
2839 
2840 	/// Addition for convertible unit_t types with a decibel_scale
2841 	template<class UnitTypeLhs, class UnitTypeRhs,
2842 		std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
operator +(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2843 	constexpr inline auto operator+(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<squared<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>>, typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type, decibel_scale>
2844 	{
2845 		using LhsUnits = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2846 		using RhsUnits = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2847 		using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type;
2848 
2849 		return unit_t<compound_unit<squared<LhsUnits>>, underlying_type, decibel_scale>
2850 			(lhs.template toLinearized<underlying_type>() * convert<RhsUnits, LhsUnits>(rhs.template toLinearized<underlying_type>()), std::true_type());
2851 	}
2852 
2853 	/// Addition between unit_t types with a decibel_scale and dimensionless dB units
2854 	template<class UnitTypeLhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value, int> = 0>
operator +(const UnitTypeLhs & lhs,const dimensionless::dB_t & rhs)2855 	constexpr inline UnitTypeLhs operator+(const UnitTypeLhs& lhs, const dimensionless::dB_t& rhs) noexcept
2856 	{
2857 		using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type;
2858 		return UnitTypeLhs(lhs.template toLinearized<underlying_type>() * rhs.template toLinearized<underlying_type>(), std::true_type());
2859 	}
2860 
2861 	/// Addition between unit_t types with a decibel_scale and dimensionless dB units
2862 	template<class UnitTypeRhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
operator +(const dimensionless::dB_t & lhs,const UnitTypeRhs & rhs)2863 	constexpr inline UnitTypeRhs operator+(const dimensionless::dB_t& lhs, const UnitTypeRhs& rhs) noexcept
2864 	{
2865 		using underlying_type = typename units::traits::unit_t_traits<UnitTypeRhs>::underlying_type;
2866 		return UnitTypeRhs(lhs.template toLinearized<underlying_type>() * rhs.template toLinearized<underlying_type>(), std::true_type());
2867 	}
2868 
2869 	/// Subtraction for convertible unit_t types with a decibel_scale
2870 	template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
operator -(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2871 	constexpr inline auto operator-(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type, inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>, typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type, decibel_scale>
2872 	{
2873 		using LhsUnits = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2874 		using RhsUnits = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2875 		using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type;
2876 
2877 		return unit_t<compound_unit<LhsUnits, inverse<RhsUnits>>, underlying_type, decibel_scale>
2878 			(lhs.template toLinearized<underlying_type>() / convert<RhsUnits, LhsUnits>(rhs.template toLinearized<underlying_type>()), std::true_type());
2879 	}
2880 
2881 	/// Subtraction between unit_t types with a decibel_scale and dimensionless dB units
2882 	template<class UnitTypeLhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value, int> = 0>
operator -(const UnitTypeLhs & lhs,const dimensionless::dB_t & rhs)2883 	constexpr inline UnitTypeLhs operator-(const UnitTypeLhs& lhs, const dimensionless::dB_t& rhs) noexcept
2884 	{
2885 		using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type;
2886 		return UnitTypeLhs(lhs.template toLinearized<underlying_type>() / rhs.template toLinearized<underlying_type>(), std::true_type());
2887 	}
2888 
2889 	/// Subtraction between unit_t types with a decibel_scale and dimensionless dB units
2890 	template<class UnitTypeRhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
operator -(const dimensionless::dB_t & lhs,const UnitTypeRhs & rhs)2891 	constexpr inline auto operator-(const dimensionless::dB_t& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>, typename units::traits::unit_t_traits<UnitTypeRhs>::underlying_type, decibel_scale>
2892 	{
2893 		using RhsUnits = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2894 		using underlying_type = typename units::traits::unit_t_traits<RhsUnits>::underlying_type;
2895 
2896 		return unit_t<inverse<RhsUnits>, underlying_type, decibel_scale>
2897 			(lhs.template toLinearized<underlying_type>() / rhs.template toLinearized<underlying_type>(), std::true_type());
2898 	}
2899 
2900 	//----------------------------------
2901 	//	UNIT RATIO CLASS
2902 	//----------------------------------
2903 
2904 	/** @cond */	// DOXYGEN IGNORE
2905 	namespace detail
2906 	{
2907 		template<class Units>
2908 		struct _unit_value_t {};
2909 	}
2910 	/** @endcond */	// END DOXYGEN IGNORE
2911 
2912 	namespace traits
2913 	{
2914 #ifdef FOR_DOXYGEN_PURPOSES_ONLY
2915 		/**
2916 		* @ingroup		TypeTraits
2917 		* @brief		Trait for accessing the publically defined types of `units::unit_value_t_traits`
2918 		* @details		The units library determines certain properties of the `unit_value_t` types passed to
2919 		*				them and what they represent by using the members of the corresponding `unit_value_t_traits`
2920 		*				instantiation.
2921 		*/
2922 		template<typename T>
2923 		struct unit_value_t_traits
2924 		{
2925 			typedef typename T::unit_type unit_type;	///< Dimension represented by the `unit_value_t`.
2926 			typedef typename T::ratio ratio;			///< Quantity represented by the `unit_value_t`, expressed as arational number.
2927 		};
2928 #endif
2929 
2930 		/** @cond */	// DOXYGEN IGNORE
2931 		/**
2932 		 * @brief		unit_value_t_traits specialization for things which are not unit_t
2933 		 * @details
2934 		 */
2935 		template<typename T, typename = void>
2936 		struct unit_value_t_traits
2937 		{
2938 			typedef void unit_type;
2939 			typedef void ratio;
2940 		};
2941 
2942 		/**
2943 		 * @ingroup		TypeTraits
2944 		 * @brief		Trait for accessing the publically defined types of `units::unit_value_t_traits`
2945 		 * @details
2946 		 */
2947 		template<typename T>
2948 		struct unit_value_t_traits <T, typename void_t<
2949 			typename T::unit_type,
2950 			typename T::ratio>::type>
2951 		{
2952 			typedef typename T::unit_type unit_type;
2953 			typedef typename T::ratio ratio;
2954 		};
2955 		/** @endcond */	// END DOXYGEN IGNORE
2956 	}
2957 
2958 	//------------------------------------------------------------------------------
2959 	//	COMPILE-TIME UNIT VALUES AND ARITHMETIC
2960 	//------------------------------------------------------------------------------
2961 
2962 	/**
2963 	 * @ingroup		UnitContainers
2964 	 * @brief		Stores a rational unit value as a compile-time constant
2965 	 * @details		unit_value_t is useful for performing compile-time arithmetic on known
2966 	 *				unit quantities.
2967 	 * @tparam		Units	units represented by the `unit_value_t`
2968 	 * @tparam		Num		numerator of the represented value.
2969 	 * @tparam		Denom	denominator of the represented value.
2970 	 * @sa			unit_value_t_traits to access information about the properties of the class,
2971 	 *				such as it's unit type and rational value.
2972 	 * @note		This is intentionally identical in concept to a `std::ratio`.
2973 	 *
2974 	 */
2975 	template<typename Units, std::uintmax_t Num, std::uintmax_t Denom = 1>
2976 	struct unit_value_t : units::detail::_unit_value_t<Units>
2977 	{
2978 		typedef Units unit_type;
2979 		typedef std::ratio<Num, Denom> ratio;
2980 
2981 		static_assert(traits::is_unit<Units>::value, "Template parameter `Units` must be a unit type.");
valueunits::unit_value_t2982 		static constexpr const unit_t<Units> value() { return unit_t<Units>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den); }
2983 	};
2984 
2985 	namespace traits
2986 	{
2987 		/**
2988 		 * @ingroup		TypeTraits
2989 		 * @brief		Trait which tests whether a type is a unit_value_t representing the given unit type.
2990 		 * @details		e.g. `is_unit_value_t<meters, myType>::value` would test that `myType` is a
2991 		 *				`unit_value_t<meters>`.
2992 		 * @tparam		Units	units that the `unit_value_t` is supposed to have.
2993 		 * @tparam		T		type to test.
2994 		 */
2995 		template<typename T, typename Units = typename traits::unit_value_t_traits<T>::unit_type>
2996 		struct is_unit_value_t : std::integral_constant<bool,
2997 			std::is_base_of<units::detail::_unit_value_t<Units>, T>::value>
2998 		{};
2999 
3000 		/**
3001 		 * @ingroup		TypeTraits
3002 		 * @brief		Trait which tests whether type T is a unit_value_t with a unit type in the given category.
3003 		 * @details		e.g. `is_unit_value_t_category<units::category::length, unit_value_t<feet>>::value` would be true
3004 		 */
3005 		template<typename Category, typename T>
3006 		struct is_unit_value_t_category : std::integral_constant<bool,
3007 			std::is_same<units::traits::base_unit_of<typename traits::unit_value_t_traits<T>::unit_type>, Category>::value>
3008 		{
3009 			static_assert(is_base_unit<Category>::value, "Template parameter `Category` must be a `base_unit` type.");
3010 		};
3011 	}
3012 
3013 	/** @cond */	// DOXYGEN IGNORE
3014 	namespace detail
3015 	{
3016 		// base class for common arithmetic
3017 		template<class U1, class U2>
3018 		struct unit_value_arithmetic
3019 		{
3020 			static_assert(traits::is_unit_value_t<U1>::value, "Template parameter `U1` must be a `unit_value_t` type.");
3021 			static_assert(traits::is_unit_value_t<U2>::value, "Template parameter `U2` must be a `unit_value_t` type.");
3022 
3023 			using _UNIT1 = typename traits::unit_value_t_traits<U1>::unit_type;
3024 			using _UNIT2 = typename traits::unit_value_t_traits<U2>::unit_type;
3025 			using _CONV1 = typename units::traits::unit_traits<_UNIT1>::conversion_ratio;
3026 			using _CONV2 = typename units::traits::unit_traits<_UNIT2>::conversion_ratio;
3027 			using _RATIO1 = typename traits::unit_value_t_traits<U1>::ratio;
3028 			using _RATIO2 = typename traits::unit_value_t_traits<U2>::ratio;
3029 			using _RATIO2CONV = typename std::ratio_divide<std::ratio_multiply<_RATIO2, _CONV2>, _CONV1>;
3030 			using _PI_EXP = std::ratio_subtract<typename units::traits::unit_traits<_UNIT2>::pi_exponent_ratio, typename units::traits::unit_traits<_UNIT1>::pi_exponent_ratio>;
3031 		};
3032 	}
3033 	/** @endcond */	// END DOXYGEN IGNORE
3034 
3035 	/**
3036 	 * @ingroup		CompileTimeUnitManipulators
3037 	 * @brief		adds two unit_value_t types at compile-time
3038 	 * @details		The resulting unit will the the `unit_type` of `U1`
3039 	 * @tparam		U1	left-hand `unit_value_t`
3040 	 * @tparam		U2	right-hand `unit_value_t`
3041 	 * @sa			unit_value_t_traits to access information about the properties of the class,
3042 	 *				such as it's unit type and rational value.
3043 	 * @note		very similar in concept to `std::ratio_add`
3044 	 */
3045 	template<class U1, class U2>
3046 	struct unit_value_add : units::detail::unit_value_arithmetic<U1, U2>, units::detail::_unit_value_t<typename traits::unit_value_t_traits<U1>::unit_type>
3047 	{
3048 		/** @cond */	// DOXYGEN IGNORE
3049 		using Base = units::detail::unit_value_arithmetic<U1, U2>;
3050 		typedef typename Base::_UNIT1 unit_type;
3051 		using ratio = std::ratio_add<typename Base::_RATIO1, typename Base::_RATIO2CONV>;
3052 
3053 		static_assert(traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, "Unit types are not compatible.");
3054 		/** @endcond */	// END DOXYGEN IGNORE
3055 
3056 		/**
3057 		 * @brief		Value of sum
3058 		 * @details		Returns the calculated value of the sum of `U1` and `U2`, in the same
3059 		 *				units as `U1`.
3060 		 * @returns		Value of the sum in the appropriate units.
3061 		 */
valueunits::unit_value_add3062 		static constexpr const unit_t<unit_type> value() noexcept
3063 		{
3064 			using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
3065 			return value(UsePi());
3066 		}
3067 
3068 		/** @cond */	// DOXYGEN IGNORE
3069 		// value if PI isn't involved
valueunits::unit_value_add3070 		static constexpr const unit_t<unit_type> value(std::false_type) noexcept
3071 		{
3072 			return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
3073 		}
3074 
3075 		// value if PI *is* involved
valueunits::unit_value_add3076 		static constexpr const unit_t<unit_type> value(std::true_type) noexcept
3077 		{
3078 			return unit_t<unit_type>(((UNIT_LIB_DEFAULT_TYPE)Base::_RATIO1::num / Base::_RATIO1::den) +
3079 			((UNIT_LIB_DEFAULT_TYPE)Base::_RATIO2CONV::num / Base::_RATIO2CONV::den) * std::pow(units::constants::detail::PI_VAL, ((UNIT_LIB_DEFAULT_TYPE)Base::_PI_EXP::num / Base::_PI_EXP::den)));
3080 		}
3081 		/** @endcond */	// END DOXYGEN IGNORE
3082 	};
3083 
3084 	/**
3085 	 * @ingroup		CompileTimeUnitManipulators
3086 	 * @brief		subtracts two unit_value_t types at compile-time
3087 	 * @details		The resulting unit will the the `unit_type` of `U1`
3088 	 * @tparam		U1	left-hand `unit_value_t`
3089 	 * @tparam		U2	right-hand `unit_value_t`
3090 	 * @sa			unit_value_t_traits to access information about the properties of the class,
3091 	 *				such as it's unit type and rational value.
3092 	 * @note		very similar in concept to `std::ratio_subtract`
3093 	 */
3094 	template<class U1, class U2>
3095 	struct unit_value_subtract : units::detail::unit_value_arithmetic<U1, U2>, units::detail::_unit_value_t<typename traits::unit_value_t_traits<U1>::unit_type>
3096 	{
3097 		/** @cond */	// DOXYGEN IGNORE
3098 		using Base = units::detail::unit_value_arithmetic<U1, U2>;
3099 
3100 		typedef typename Base::_UNIT1 unit_type;
3101 		using ratio = std::ratio_subtract<typename Base::_RATIO1, typename Base::_RATIO2CONV>;
3102 
3103 		static_assert(traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, "Unit types are not compatible.");
3104 		/** @endcond */	// END DOXYGEN IGNORE
3105 
3106 		/**
3107 		 * @brief		Value of difference
3108 		 * @details		Returns the calculated value of the difference of `U1` and `U2`, in the same
3109 		 *				units as `U1`.
3110 		 * @returns		Value of the difference in the appropriate units.
3111 		 */
valueunits::unit_value_subtract3112 		static constexpr const unit_t<unit_type> value() noexcept
3113 		{
3114 			using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
3115 			return value(UsePi());
3116 		}
3117 
3118 		/** @cond */	// DOXYGEN IGNORE
3119 		// value if PI isn't involved
valueunits::unit_value_subtract3120 		static constexpr const unit_t<unit_type> value(std::false_type) noexcept
3121 		{
3122 			return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
3123 		}
3124 
3125 		// value if PI *is* involved
valueunits::unit_value_subtract3126 		static constexpr const unit_t<unit_type> value(std::true_type) noexcept
3127 		{
3128 			return unit_t<unit_type>(((UNIT_LIB_DEFAULT_TYPE)Base::_RATIO1::num / Base::_RATIO1::den) - ((UNIT_LIB_DEFAULT_TYPE)Base::_RATIO2CONV::num / Base::_RATIO2CONV::den)
3129 				* std::pow(units::constants::detail::PI_VAL, ((UNIT_LIB_DEFAULT_TYPE)Base::_PI_EXP::num / Base::_PI_EXP::den)));
3130 		}
3131 		/** @endcond */	// END DOXYGEN IGNORE	};
3132 	};
3133 
3134 	/**
3135 	 * @ingroup		CompileTimeUnitManipulators
3136 	 * @brief		multiplies two unit_value_t types at compile-time
3137 	 * @details		The resulting unit will the the `unit_type` of `U1 * U2`
3138 	 * @tparam		U1	left-hand `unit_value_t`
3139 	 * @tparam		U2	right-hand `unit_value_t`
3140 	 * @sa			unit_value_t_traits to access information about the properties of the class,
3141 	 *				such as it's unit type and rational value.
3142 	 * @note		very similar in concept to `std::ratio_multiply`
3143 	 */
3144 	template<class U1, class U2>
3145 	struct unit_value_multiply : units::detail::unit_value_arithmetic<U1, U2>,
3146 		units::detail::_unit_value_t<typename std::conditional<traits::is_convertible_unit<typename traits::unit_value_t_traits<U1>::unit_type,
3147 			typename traits::unit_value_t_traits<U2>::unit_type>::value, compound_unit<squared<typename traits::unit_value_t_traits<U1>::unit_type>>,
3148 			compound_unit<typename traits::unit_value_t_traits<U1>::unit_type, typename traits::unit_value_t_traits<U2>::unit_type>>::type>
3149 	{
3150 		/** @cond */	// DOXYGEN IGNORE
3151 		using Base = units::detail::unit_value_arithmetic<U1, U2>;
3152 
3153 		using unit_type = std::conditional_t<traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, compound_unit<squared<typename Base::_UNIT1>>, compound_unit<typename Base::_UNIT1, typename Base::_UNIT2>>;
3154 		using ratio = std::conditional_t<traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, std::ratio_multiply<typename Base::_RATIO1, typename Base::_RATIO2CONV>, std::ratio_multiply<typename Base::_RATIO1, typename Base::_RATIO2>>;
3155 		/** @endcond */	// END DOXYGEN IGNORE
3156 
3157 		/**
3158 		 * @brief		Value of product
3159 		 * @details		Returns the calculated value of the product of `U1` and `U2`, in units
3160 		 *				of `U1 x U2`.
3161 		 * @returns		Value of the product in the appropriate units.
3162 		 */
valueunits::unit_value_multiply3163 		static constexpr const unit_t<unit_type> value() noexcept
3164 		{
3165 			using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
3166 			return value(UsePi());
3167 		}
3168 
3169 		/** @cond */	// DOXYGEN IGNORE
3170 		// value if PI isn't involved
valueunits::unit_value_multiply3171 		static constexpr const unit_t<unit_type> value(std::false_type) noexcept
3172 		{
3173 			return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
3174 		}
3175 
3176 		// value if PI *is* involved
valueunits::unit_value_multiply3177 		static constexpr const unit_t<unit_type> value(std::true_type) noexcept
3178 		{
3179 			return unit_t<unit_type>(((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den) * std::pow(units::constants::detail::PI_VAL, ((UNIT_LIB_DEFAULT_TYPE)Base::_PI_EXP::num / Base::_PI_EXP::den)));
3180 		}
3181 		/** @endcond */	// END DOXYGEN IGNORE
3182 	};
3183 
3184 	/**
3185 	 * @ingroup		CompileTimeUnitManipulators
3186 	 * @brief		divides two unit_value_t types at compile-time
3187 	 * @details		The resulting unit will the the `unit_type` of `U1`
3188 	 * @tparam		U1	left-hand `unit_value_t`
3189 	 * @tparam		U2	right-hand `unit_value_t`
3190 	 * @sa			unit_value_t_traits to access information about the properties of the class,
3191 	 *				such as it's unit type and rational value.
3192 	 * @note		very similar in concept to `std::ratio_divide`
3193 	 */
3194 	template<class U1, class U2>
3195 	struct unit_value_divide : units::detail::unit_value_arithmetic<U1, U2>,
3196 		units::detail::_unit_value_t<typename std::conditional<traits::is_convertible_unit<typename traits::unit_value_t_traits<U1>::unit_type,
3197 		typename traits::unit_value_t_traits<U2>::unit_type>::value, dimensionless::scalar, compound_unit<typename traits::unit_value_t_traits<U1>::unit_type,
3198 		inverse<typename traits::unit_value_t_traits<U2>::unit_type>>>::type>
3199 	{
3200 		/** @cond */	// DOXYGEN IGNORE
3201 		using Base = units::detail::unit_value_arithmetic<U1, U2>;
3202 
3203 		using unit_type = std::conditional_t<traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, dimensionless::scalar, compound_unit<typename Base::_UNIT1, inverse<typename Base::_UNIT2>>>;
3204 		using ratio = std::conditional_t<traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, std::ratio_divide<typename Base::_RATIO1, typename Base::_RATIO2CONV>, std::ratio_divide<typename Base::_RATIO1, typename Base::_RATIO2>>;
3205 		/** @endcond */	// END DOXYGEN IGNORE
3206 
3207 		/**
3208 		 * @brief		Value of quotient
3209 		 * @details		Returns the calculated value of the quotient of `U1` and `U2`, in units
3210 		 *				of `U1 x U2`.
3211 		 * @returns		Value of the quotient in the appropriate units.
3212 		 */
valueunits::unit_value_divide3213 		static constexpr const unit_t<unit_type> value() noexcept
3214 		{
3215 			using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
3216 			return value(UsePi());
3217 		}
3218 
3219 		/** @cond */	// DOXYGEN IGNORE
3220 		// value if PI isn't involved
valueunits::unit_value_divide3221 		static constexpr const unit_t<unit_type> value(std::false_type) noexcept
3222 		{
3223 			return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
3224 		}
3225 
3226 		// value if PI *is* involved
valueunits::unit_value_divide3227 		static constexpr const unit_t<unit_type> value(std::true_type) noexcept
3228 		{
3229 			return unit_t<unit_type>(((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den) * std::pow(units::constants::detail::PI_VAL, ((UNIT_LIB_DEFAULT_TYPE)Base::_PI_EXP::num / Base::_PI_EXP::den)));
3230 		}
3231 		/** @endcond */	// END DOXYGEN IGNORE
3232 	};
3233 
3234 	/**
3235 	 * @ingroup		CompileTimeUnitManipulators
3236 	 * @brief		raises unit_value_to a power at compile-time
3237 	 * @details		The resulting unit will the `unit_type` of `U1` squared
3238 	 * @tparam		U1	`unit_value_t` to take the exponentiation of.
3239 	 * @sa			unit_value_t_traits to access information about the properties of the class,
3240 	 *				such as it's unit type and rational value.
3241 	 * @note		very similar in concept to `units::math::pow`
3242 	 */
3243 	template<class U1, int power>
3244 	struct unit_value_power : units::detail::unit_value_arithmetic<U1, U1>, units::detail::_unit_value_t<typename units::detail::power_of_unit<power, typename traits::unit_value_t_traits<U1>::unit_type>::type>
3245 	{
3246 		/** @cond */	// DOXYGEN IGNORE
3247 		using Base = units::detail::unit_value_arithmetic<U1, U1>;
3248 
3249 		using unit_type = typename units::detail::power_of_unit<power, typename Base::_UNIT1>::type;
3250 		using ratio = typename units::detail::power_of_ratio<power, typename Base::_RATIO1>::type;
3251 		using pi_exponent = std::ratio_multiply<std::ratio<power>, typename Base::_UNIT1::pi_exponent_ratio>;
3252 		/** @endcond */	// END DOXYGEN IGNORE
3253 
3254 		/**
3255 		 * @brief		Value of exponentiation
3256 		 * @details		Returns the calculated value of the exponentiation of `U1`, in units
3257 		 *				of `U1^power`.
3258 		 * @returns		Value of the exponentiation in the appropriate units.
3259 		 */
valueunits::unit_value_power3260 		static constexpr const unit_t<unit_type> value() noexcept
3261 		{
3262 			using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
3263 			return value(UsePi());
3264 		}
3265 
3266 		/** @cond */	// DOXYGEN IGNORE
3267 		// value if PI isn't involved
valueunits::unit_value_power3268 		static constexpr const unit_t<unit_type> value(std::false_type) noexcept
3269 		{
3270 			return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
3271 		}
3272 
3273 		// value if PI *is* involved
valueunits::unit_value_power3274 		static constexpr const unit_t<unit_type> value(std::true_type) noexcept
3275 		{
3276 			return unit_t<unit_type>(((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den) * std::pow(units::constants::detail::PI_VAL, ((UNIT_LIB_DEFAULT_TYPE)pi_exponent::num / pi_exponent::den)));
3277 		}
3278 		/** @endcond */	// END DOXYGEN IGNORE	};
3279 	};
3280 
3281 	/**
3282 	 * @ingroup		CompileTimeUnitManipulators
3283 	 * @brief		calculates square root of unit_value_t at compile-time
3284 	 * @details		The resulting unit will the square root `unit_type` of `U1`
3285 	 * @tparam		U1	`unit_value_t` to take the square root of.
3286 	 * @sa			unit_value_t_traits to access information about the properties of the class,
3287 	 *				such as it's unit type and rational value.
3288 	 * @note		very similar in concept to `units::ratio_sqrt`
3289 	 */
3290 	template<class U1, std::intmax_t Eps = 10000000000>
3291 	struct unit_value_sqrt : units::detail::unit_value_arithmetic<U1, U1>, units::detail::_unit_value_t<square_root<typename traits::unit_value_t_traits<U1>::unit_type, Eps>>
3292 	{
3293 		/** @cond */	// DOXYGEN IGNORE
3294 		using Base = units::detail::unit_value_arithmetic<U1, U1>;
3295 
3296 		using unit_type = square_root<typename Base::_UNIT1, Eps>;
3297 		using ratio = ratio_sqrt<typename Base::_RATIO1, Eps>;
3298 		using pi_exponent = ratio_sqrt<typename Base::_UNIT1::pi_exponent_ratio, Eps>;
3299 		/** @endcond */	// END DOXYGEN IGNORE
3300 
3301 		/**
3302 		 * @brief		Value of square root
3303 		 * @details		Returns the calculated value of the square root of `U1`, in units
3304 		 *				of `U1^1/2`.
3305 		 * @returns		Value of the square root in the appropriate units.
3306 		 */
valueunits::unit_value_sqrt3307 		static constexpr const unit_t<unit_type> value() noexcept
3308 		{
3309 			using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
3310 			return value(UsePi());
3311 		}
3312 
3313 		/** @cond */	// DOXYGEN IGNORE
3314 		// value if PI isn't involved
valueunits::unit_value_sqrt3315 		static constexpr const unit_t<unit_type> value(std::false_type) noexcept
3316 		{
3317 			return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
3318 		}
3319 
3320 		// value if PI *is* involved
valueunits::unit_value_sqrt3321 		static constexpr const unit_t<unit_type> value(std::true_type) noexcept
3322 		{
3323 			return unit_t<unit_type>(((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den) * std::pow(units::constants::detail::PI_VAL, ((UNIT_LIB_DEFAULT_TYPE)pi_exponent::num / pi_exponent::den)));
3324 		}
3325 		/** @endcond */	// END DOXYGEN IGNORE
3326 	};
3327 
3328 	//------------------------------
3329 	//	LITERALS
3330 	//------------------------------
3331 
3332 	/**
3333 	 * @namespace	units::literals
3334 	 * @brief		namespace for unit literal definitions of all categories.
3335 	 * @details		Literals allow for declaring unit types using suffix values. For example, a type
3336 	 *				of `meter_t(6.2)` could be declared as `6.2_m`. All literals use an underscore
3337 	 *				followed by the abbreviation for the unit. To enable literal syntax in your code,
3338 	 *				include the statement `using namespace units::literals`.
3339 	 * @anchor		unitLiterals
3340 	 * @sa			See unit_t for more information on unit type containers.
3341 	 */
3342 
3343 	//------------------------------
3344 	//	LENGTH UNITS
3345 	//------------------------------
3346 
3347 	/**
3348 	 * @namespace	units::length
3349 	 * @brief		namespace for unit types and containers representing length values
3350 	 * @details		The SI unit for length is `meters`, and the corresponding `base_unit` category is
3351 	 *				`length_unit`.
3352 	 * @anchor		lengthContainers
3353 	 * @sa			See unit_t for more information on unit type containers.
3354 	 */
3355 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_LENGTH_UNITS)
3356 	UNIT_ADD_WITH_METRIC_PREFIXES(length, meter, meters, m, unit<std::ratio<1>, units::category::length_unit>)
3357 	UNIT_ADD(length, foot, feet, ft, unit<std::ratio<381, 1250>, meters>)
3358 	UNIT_ADD(length, mil, mils, mil, unit<std::ratio<1000>, feet>)
3359 	UNIT_ADD(length, inch, inches, in, unit<std::ratio<1, 12>, feet>)
3360 	UNIT_ADD(length, mile,   miles,    mi,    unit<std::ratio<5280>, feet>)
3361 	UNIT_ADD(length, nauticalMile, nauticalMiles, nmi, unit<std::ratio<1852>, meters>)
3362 	UNIT_ADD(length, astronicalUnit, astronicalUnits, au, unit<std::ratio<149597870700>, meters>)
3363 	UNIT_ADD(length, lightyear, lightyears, ly, unit<std::ratio<9460730472580800>, meters>)
3364 	UNIT_ADD(length, parsec, parsecs, pc, unit<std::ratio<648000>, astronicalUnits, std::ratio<-1>>)
3365 	UNIT_ADD(length, angstrom, angstroms, angstrom, unit<std::ratio<1, 10>, nanometers>)
3366 	UNIT_ADD(length, cubit, cubits, cbt, unit<std::ratio<18>, inches>)
3367 	UNIT_ADD(length, fathom, fathoms, ftm, unit<std::ratio<6>, feet>)
3368 	UNIT_ADD(length, chain, chains, ch, unit<std::ratio<66>, feet>)
3369 	UNIT_ADD(length, furlong, furlongs, fur, unit<std::ratio<10>, chains>)
3370 	UNIT_ADD(length, hand, hands, hand, unit<std::ratio<4>, inches>)
3371 	UNIT_ADD(length, league, leagues, lea, unit<std::ratio<3>, miles>)
3372 	UNIT_ADD(length, nauticalLeague, nauticalLeagues, nl, unit<std::ratio<3>, nauticalMiles>)
3373 	UNIT_ADD(length, yard, yards, yd, unit<std::ratio<3>, feet>)
3374 
3375 	UNIT_ADD_CATEGORY_TRAIT(length)
3376 #endif
3377 
3378 	//------------------------------
3379 	//	MASS UNITS
3380 	//------------------------------
3381 
3382 	/**
3383 	 * @namespace	units::mass
3384 	 * @brief		namespace for unit types and containers representing mass values
3385 	 * @details		The SI unit for mass is `kilograms`, and the corresponding `base_unit` category is
3386 	 *				`mass_unit`.
3387 	 * @anchor		massContainers
3388 	 * @sa			See unit_t for more information on unit type containers.
3389 	 */
3390 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_MASS_UNITS)
3391 	UNIT_ADD_WITH_METRIC_PREFIXES(mass, gram, grams, g, unit<std::ratio<1, 1000>, units::category::mass_unit>)
3392 	UNIT_ADD(mass, metric_ton, metric_tons, t, unit<std::ratio<1000>, kilograms>)
3393 	UNIT_ADD(mass, pound, pounds, lb, unit<std::ratio<45359237, 100000000>, kilograms>)
3394 	UNIT_ADD(mass, long_ton, long_tons, ln_t, unit<std::ratio<2240>, pounds>)
3395 	UNIT_ADD(mass, short_ton, short_tons, sh_t, unit<std::ratio<2000>, pounds>)
3396 	UNIT_ADD(mass, stone, stone, st, unit<std::ratio<14>, pounds>)
3397 	UNIT_ADD(mass, ounce, ounces, oz, unit<std::ratio<1, 16>, pounds>)
3398 	UNIT_ADD(mass, carat, carats, ct, unit<std::ratio<200>, milligrams>)
3399 	UNIT_ADD(mass, slug, slugs, slug, unit<std::ratio<145939029, 10000000>, kilograms>)
3400 
3401 	UNIT_ADD_CATEGORY_TRAIT(mass)
3402 #endif
3403 
3404 	//------------------------------
3405 	//	TIME UNITS
3406 	//------------------------------
3407 
3408 	/**
3409 	 * @namespace	units::time
3410 	 * @brief		namespace for unit types and containers representing time values
3411 	 * @details		The SI unit for time is `seconds`, and the corresponding `base_unit` category is
3412 	 *				`time_unit`.
3413 	 * @anchor		timeContainers
3414 	 * @sa			See unit_t for more information on unit type containers.
3415 	 */
3416 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_TIME_UNITS)
3417 	UNIT_ADD_WITH_METRIC_PREFIXES(time, second, seconds, s, unit<std::ratio<1>, units::category::time_unit>)
3418 	UNIT_ADD(time, minute, minutes, min, unit<std::ratio<60>, seconds>)
3419 	UNIT_ADD(time, hour, hours, hr, unit<std::ratio<60>, minutes>)
3420 	UNIT_ADD(time, day, days, d, unit<std::ratio<24>, hours>)
3421 	UNIT_ADD(time, week, weeks, wk, unit<std::ratio<7>, days>)
3422 	UNIT_ADD(time, year, years, yr, unit<std::ratio<365>, days>)
3423 	UNIT_ADD(time, julian_year, julian_years, a_j,	unit<std::ratio<31557600>, seconds>)
3424 	UNIT_ADD(time, gregorian_year, gregorian_years, a_g, unit<std::ratio<31556952>, seconds>)
3425 
3426 	UNIT_ADD_CATEGORY_TRAIT(time)
3427 #endif
3428 
3429 	//------------------------------
3430 	//	ANGLE UNITS
3431 	//------------------------------
3432 
3433 	/**
3434 	 * @namespace	units::angle
3435 	 * @brief		namespace for unit types and containers representing angle values
3436 	 * @details		The SI unit for angle is `radians`, and the corresponding `base_unit` category is
3437 	 *				`angle_unit`.
3438 	 * @anchor		angleContainers
3439 	 * @sa			See unit_t for more information on unit type containers.
3440 	 */
3441 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
3442 	UNIT_ADD_WITH_METRIC_PREFIXES(angle, radian, radians, rad, unit<std::ratio<1>, units::category::angle_unit>)
3443 	UNIT_ADD(angle, degree, degrees, deg, unit<std::ratio<1, 180>, radians, std::ratio<1>>)
3444 	UNIT_ADD(angle, arcminute, arcminutes, arcmin, unit<std::ratio<1, 60>, degrees>)
3445 	UNIT_ADD(angle, arcsecond, arcseconds, arcsec, unit<std::ratio<1, 60>, arcminutes>)
3446 	UNIT_ADD(angle, milliarcsecond, milliarcseconds, mas, milli<arcseconds>)
3447 	UNIT_ADD(angle, turn, turns, tr, unit<std::ratio<2>, radians, std::ratio<1>>)
3448 	UNIT_ADD(angle, gradian, gradians, gon, unit<std::ratio<1, 400>, turns>)
3449 
3450 	UNIT_ADD_CATEGORY_TRAIT(angle)
3451 #endif
3452 
3453 	//------------------------------
3454 	//	UNITS OF CURRENT
3455 	//------------------------------
3456 	/**
3457 	 * @namespace	units::current
3458 	 * @brief		namespace for unit types and containers representing current values
3459 	 * @details		The SI unit for current is `amperes`, and the corresponding `base_unit` category is
3460 	 *				`current_unit`.
3461 	 * @anchor		currentContainers
3462 	 * @sa			See unit_t for more information on unit type containers.
3463 	 */
3464 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_CURRENT_UNITS)
3465 	UNIT_ADD_WITH_METRIC_PREFIXES(current, ampere, amperes, A, unit<std::ratio<1>, units::category::current_unit>)
3466 
3467 	UNIT_ADD_CATEGORY_TRAIT(current)
3468 #endif
3469 
3470 	//------------------------------
3471 	//	UNITS OF TEMPERATURE
3472 	//------------------------------
3473 
3474 	// NOTE: temperature units have special conversion overloads, since they
3475 	// require translations and aren't a reversible transform.
3476 
3477 	/**
3478 	 * @namespace	units::temperature
3479 	 * @brief		namespace for unit types and containers representing temperature values
3480 	 * @details		The SI unit for temperature is `kelvin`, and the corresponding `base_unit` category is
3481 	 *				`temperature_unit`.
3482 	 * @anchor		temperatureContainers
3483 	 * @sa			See unit_t for more information on unit type containers.
3484 	 */
3485 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_TEMPERATURE_UNITS)
3486 	UNIT_ADD(temperature, kelvin, kelvin, K, unit<std::ratio<1>, units::category::temperature_unit>)
3487 	UNIT_ADD(temperature, celsius, celsius, degC, unit<std::ratio<1>, kelvin, std::ratio<0>, std::ratio<27315, 100>>)
3488 	UNIT_ADD(temperature, fahrenheit, fahrenheit, degF, unit<std::ratio<5, 9>, celsius, std::ratio<0>, std::ratio<-160, 9>>)
3489 	UNIT_ADD(temperature, reaumur, reaumur, Re, unit<std::ratio<10, 8>, celsius>)
3490 	UNIT_ADD(temperature, rankine, rankine, Ra, unit<std::ratio<5, 9>, kelvin>)
3491 
3492 	UNIT_ADD_CATEGORY_TRAIT(temperature)
3493 #endif
3494 
3495 	//------------------------------
3496 	//	UNITS OF AMOUNT OF SUBSTANCE
3497 	//------------------------------
3498 
3499 	/**
3500 	 * @namespace	units::substance
3501 	 * @brief		namespace for unit types and containers representing substance values
3502 	 * @details		The SI unit for substance is `moles`, and the corresponding `base_unit` category is
3503 	 *				`substance_unit`.
3504 	 * @anchor		substanceContainers
3505 	 * @sa			See unit_t for more information on unit type containers.
3506 	 */
3507 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_SUBSTANCE_UNITS)
3508 	UNIT_ADD(substance, mole, moles, mol, unit<std::ratio<1>, units::category::substance_unit>)
3509 
3510 	UNIT_ADD_CATEGORY_TRAIT(substance)
3511 #endif
3512 
3513 	//------------------------------
3514 	//	UNITS OF LUMINOUS INTENSITY
3515 	//------------------------------
3516 
3517 	/**
3518 	 * @namespace	units::luminous_intensity
3519 	 * @brief		namespace for unit types and containers representing luminous_intensity values
3520 	 * @details		The SI unit for luminous_intensity is `candelas`, and the corresponding `base_unit` category is
3521 	 *				`luminous_intensity_unit`.
3522 	 * @anchor		luminousIntensityContainers
3523 	 * @sa			See unit_t for more information on unit type containers.
3524 	 */
3525 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_LUMINOUS_INTENSITY_UNITS)
3526 	UNIT_ADD_WITH_METRIC_PREFIXES(luminous_intensity, candela, candelas, cd, unit<std::ratio<1>, units::category::luminous_intensity_unit>)
3527 
3528 	UNIT_ADD_CATEGORY_TRAIT(luminous_intensity)
3529 #endif
3530 
3531 	//------------------------------
3532 	//	UNITS OF SOLID ANGLE
3533 	//------------------------------
3534 
3535 	/**
3536 	 * @namespace	units::solid_angle
3537 	 * @brief		namespace for unit types and containers representing solid_angle values
3538 	 * @details		The SI unit for solid_angle is `steradians`, and the corresponding `base_unit` category is
3539 	 *				`solid_angle_unit`.
3540 	 * @anchor		solidAngleContainers
3541 	 * @sa			See unit_t for more information on unit type containers.
3542 	 */
3543 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_SOLID_ANGLE_UNITS)
3544 	UNIT_ADD_WITH_METRIC_PREFIXES(solid_angle, steradian, steradians, sr, unit<std::ratio<1>, units::category::solid_angle_unit>)
3545 	UNIT_ADD(solid_angle, degree_squared, degrees_squared, sq_deg, squared<angle::degrees>)
3546 	UNIT_ADD(solid_angle, spat, spats, sp, unit<std::ratio<4>, steradians, std::ratio<1>>)
3547 
3548 	UNIT_ADD_CATEGORY_TRAIT(solid_angle)
3549 #endif
3550 
3551 	//------------------------------
3552 	//	FREQUENCY UNITS
3553 	//------------------------------
3554 
3555 	/**
3556 	 * @namespace	units::frequency
3557 	 * @brief		namespace for unit types and containers representing frequency values
3558 	 * @details		The SI unit for frequency is `hertz`, and the corresponding `base_unit` category is
3559 	 *				`frequency_unit`.
3560 	 * @anchor		frequencyContainers
3561 	 * @sa			See unit_t for more information on unit type containers.
3562 	 */
3563 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_FREQUENCY_UNITS)
3564 	UNIT_ADD_WITH_METRIC_PREFIXES(frequency, hertz, hertz, Hz, unit<std::ratio<1>, units::category::frequency_unit>)
3565 
3566 	UNIT_ADD_CATEGORY_TRAIT(frequency)
3567 #endif
3568 
3569 	//------------------------------
3570 	//	VELOCITY UNITS
3571 	//------------------------------
3572 
3573 	/**
3574 	 * @namespace	units::velocity
3575 	 * @brief		namespace for unit types and containers representing velocity values
3576 	 * @details		The SI unit for velocity is `meters_per_second`, and the corresponding `base_unit` category is
3577 	 *				`velocity_unit`.
3578 	 * @anchor		velocityContainers
3579 	 * @sa			See unit_t for more information on unit type containers.
3580 	 */
3581 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_VELOCITY_UNITS)
3582 	UNIT_ADD(velocity, meters_per_second, meters_per_second, mps, unit<std::ratio<1>, units::category::velocity_unit>)
3583 	UNIT_ADD(velocity, feet_per_second, feet_per_second, fps, compound_unit<length::feet, inverse<time::seconds>>)
3584 	UNIT_ADD(velocity, miles_per_hour, miles_per_hour, mph, compound_unit<length::miles, inverse<time::hour>>)
3585 	UNIT_ADD(velocity, kilometers_per_hour, kilometers_per_hour, kph, compound_unit<length::kilometers, inverse<time::hour>>)
3586 	UNIT_ADD(velocity, knot, knots, kts, compound_unit<length::nauticalMiles, inverse<time::hour>>)
3587 
3588 	UNIT_ADD_CATEGORY_TRAIT(velocity)
3589 #endif
3590 
3591 	//------------------------------
3592 	//	ANGULAR VELOCITY UNITS
3593 	//------------------------------
3594 
3595 	/**
3596 	 * @namespace	units::angular_velocity
3597 	 * @brief		namespace for unit types and containers representing angular velocity values
3598 	 * @details		The SI unit for angular velocity is `radians_per_second`, and the corresponding `base_unit` category is
3599 	 *				`angular_velocity_unit`.
3600 	 * @anchor		angularVelocityContainers
3601 	 * @sa			See unit_t for more information on unit type containers.
3602 	 */
3603 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGULAR_VELOCITY_UNITS)
3604 	UNIT_ADD(angular_velocity, radians_per_second, radians_per_second, rad_per_s, unit<std::ratio<1>, units::category::angular_velocity_unit>)
3605 	UNIT_ADD(angular_velocity, degrees_per_second, degrees_per_second, deg_per_s, compound_unit<angle::degrees, inverse<time::seconds>>)
3606 	UNIT_ADD(angular_velocity, revolutions_per_minute, revolutions_per_minute, rpm, unit<std::ratio<2, 60>, radians_per_second, std::ratio<1>>)
3607 	UNIT_ADD(angular_velocity, milliarcseconds_per_year, milliarcseconds_per_year, mas_per_yr, compound_unit<angle::milliarcseconds, inverse<time::year>>)
3608 
3609 	UNIT_ADD_CATEGORY_TRAIT(angular_velocity)
3610 #endif
3611 
3612 	//------------------------------
3613 	//	UNITS OF ACCELERATION
3614 	//------------------------------
3615 
3616 	/**
3617 	 * @namespace	units::acceleration
3618 	 * @brief		namespace for unit types and containers representing acceleration values
3619 	 * @details		The SI unit for acceleration is `meters_per_second_squared`, and the corresponding `base_unit` category is
3620 	 *				`acceleration_unit`.
3621 	 * @anchor		accelerationContainers
3622 	 * @sa			See unit_t for more information on unit type containers.
3623 	 */
3624 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ACCELERATION_UNITS)
3625 	UNIT_ADD(acceleration, meters_per_second_squared, meters_per_second_squared, mps_sq, unit<std::ratio<1>, units::category::acceleration_unit>)
3626 	UNIT_ADD(acceleration, feet_per_second_squared, feet_per_second_squared, fps_sq, compound_unit<length::feet, inverse<squared<time::seconds>>>)
3627 	UNIT_ADD(acceleration, standard_gravity, standard_gravity, SG, unit<std::ratio<980665, 100000>, meters_per_second_squared>)
3628 
3629 	UNIT_ADD_CATEGORY_TRAIT(acceleration)
3630 #endif
3631 
3632 	//------------------------------
3633 	//	UNITS OF FORCE
3634 	//------------------------------
3635 
3636 	/**
3637 	 * @namespace	units::force
3638 	 * @brief		namespace for unit types and containers representing force values
3639 	 * @details		The SI unit for force is `newtons`, and the corresponding `base_unit` category is
3640 	 *				`force_unit`.
3641 	 * @anchor		forceContainers
3642 	 * @sa			See unit_t for more information on unit type containers.
3643 	 */
3644 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_FORCE_UNITS)
3645 	UNIT_ADD_WITH_METRIC_PREFIXES(force, newton, newtons, N, unit<std::ratio<1>, units::category::force_unit>)
3646 	UNIT_ADD(force, pound, pounds, lbf, compound_unit<mass::slug, length::foot, inverse<squared<time::seconds>>>)
3647 	UNIT_ADD(force, dyne, dynes, dyn, unit<std::ratio<1, 100000>, newtons>)
3648 	UNIT_ADD(force, kilopond, kiloponds, kp, compound_unit<acceleration::standard_gravity, mass::kilograms>)
3649 	UNIT_ADD(force, poundal, poundals, pdl, compound_unit<mass::pound, length::foot, inverse<squared<time::seconds>>>)
3650 
3651 	UNIT_ADD_CATEGORY_TRAIT(force)
3652 #endif
3653 
3654 	//------------------------------
3655 	//	UNITS OF PRESSURE
3656 	//------------------------------
3657 
3658 	/**
3659 	 * @namespace	units::pressure
3660 	 * @brief		namespace for unit types and containers representing pressure values
3661 	 * @details		The SI unit for pressure is `pascals`, and the corresponding `base_unit` category is
3662 	 *				`pressure_unit`.
3663 	 * @anchor		pressureContainers
3664 	 * @sa			See unit_t for more information on unit type containers.
3665 	 */
3666 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_PRESSURE_UNITS)
3667 	UNIT_ADD_WITH_METRIC_PREFIXES(pressure, pascal, pascals, Pa, unit<std::ratio<1>, units::category::pressure_unit>)
3668 	UNIT_ADD(pressure, bar, bars, bar, unit<std::ratio<100>, kilo<pascals>>)
3669 	UNIT_ADD(pressure, mbar, mbars, mbar, unit<std::ratio<1>, milli<bar>>)
3670 	UNIT_ADD(pressure, atmosphere, atmospheres, atm, unit<std::ratio<101325>, pascals>)
3671 	UNIT_ADD(pressure, pounds_per_square_inch, pounds_per_square_inch, psi, compound_unit<force::pounds, inverse<squared<length::inch>>>)
3672 	UNIT_ADD(pressure, torr, torrs, torr, unit<std::ratio<1, 760>, atmospheres>)
3673 
3674 	UNIT_ADD_CATEGORY_TRAIT(pressure)
3675 #endif
3676 
3677 	//------------------------------
3678 	//	UNITS OF CHARGE
3679 	//------------------------------
3680 
3681 	/**
3682 	 * @namespace	units::charge
3683 	 * @brief		namespace for unit types and containers representing charge values
3684 	 * @details		The SI unit for charge is `coulombs`, and the corresponding `base_unit` category is
3685 	 *				`charge_unit`.
3686 	 * @anchor		chargeContainers
3687 	 * @sa			See unit_t for more information on unit type containers.
3688 	 */
3689 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_CHARGE_UNITS)
3690 	UNIT_ADD_WITH_METRIC_PREFIXES(charge, coulomb, coulombs, C, unit<std::ratio<1>, units::category::charge_unit>)
3691 	UNIT_ADD_WITH_METRIC_PREFIXES(charge, ampere_hour, ampere_hours, Ah, compound_unit<current::ampere, time::hours>)
3692 
3693 	UNIT_ADD_CATEGORY_TRAIT(charge)
3694 #endif
3695 
3696 	//------------------------------
3697 	//	UNITS OF ENERGY
3698 	//------------------------------
3699 
3700 	/**
3701 	 * @namespace	units::energy
3702 	 * @brief		namespace for unit types and containers representing energy values
3703 	 * @details		The SI unit for energy is `joules`, and the corresponding `base_unit` category is
3704 	 *				`energy_unit`.
3705 	 * @anchor		energyContainers
3706 	 * @sa			See unit_t for more information on unit type containers.
3707 	 */
3708 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ENERGY_UNITS)
3709 	UNIT_ADD_WITH_METRIC_PREFIXES(energy, joule, joules, J, unit<std::ratio<1>, units::category::energy_unit>)
3710 	UNIT_ADD_WITH_METRIC_PREFIXES(energy, calorie, calories, cal, unit<std::ratio<4184, 1000>, joules>)
3711 	UNIT_ADD(energy, kilowatt_hour, kilowatt_hours, kWh, unit<std::ratio<36, 10>, megajoules>)
3712 	UNIT_ADD(energy, watt_hour, watt_hours, Wh, unit<std::ratio<1, 1000>, kilowatt_hours>)
3713 	UNIT_ADD(energy, british_thermal_unit, british_thermal_units, BTU, unit<std::ratio<105505585262, 100000000>, joules>)
3714 	UNIT_ADD(energy, british_thermal_unit_iso, british_thermal_units_iso, BTU_iso, unit<std::ratio<1055056, 1000>, joules>)
3715 	UNIT_ADD(energy, british_thermal_unit_59, british_thermal_units_59, BTU59, unit<std::ratio<1054804, 1000>, joules>)
3716 	UNIT_ADD(energy, therm, therms, thm, unit<std::ratio<100000>, british_thermal_units_59>)
3717 	UNIT_ADD(energy, foot_pound, foot_pounds, ftlbf, unit<std::ratio<13558179483314004, 10000000000000000>, joules>)
3718 
3719 	UNIT_ADD_CATEGORY_TRAIT(energy)
3720 #endif
3721 
3722 	//------------------------------
3723 	//	UNITS OF POWER
3724 	//------------------------------
3725 
3726 	/**
3727 	 * @namespace	units::power
3728 	 * @brief		namespace for unit types and containers representing power values
3729 	 * @details		The SI unit for power is `watts`, and the corresponding `base_unit` category is
3730 	 *				`power_unit`.
3731 	 * @anchor		powerContainers
3732 	 * @sa			See unit_t for more information on unit type containers.
3733 	 */
3734 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_POWER_UNITS)
3735 	UNIT_ADD_WITH_METRIC_PREFIXES(power, watt, watts, W, unit<std::ratio<1>, units::category::power_unit>)
3736 	UNIT_ADD(power, horsepower, horsepower, hp, unit<std::ratio<7457, 10>, watts>)
3737 	UNIT_ADD_DECIBEL(power, watt, dBW)
3738 	UNIT_ADD_DECIBEL(power, milliwatt, dBm)
3739 
3740 	UNIT_ADD_CATEGORY_TRAIT(power)
3741 #endif
3742 
3743 	//------------------------------
3744 	//	UNITS OF VOLTAGE
3745 	//------------------------------
3746 
3747 	/**
3748 	 * @namespace	units::voltage
3749 	 * @brief		namespace for unit types and containers representing voltage values
3750 	 * @details		The SI unit for voltage is `volts`, and the corresponding `base_unit` category is
3751 	 *				`voltage_unit`.
3752 	 * @anchor		voltageContainers
3753 	 * @sa			See unit_t for more information on unit type containers.
3754 	 */
3755 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_VOLTAGE_UNITS)
3756 	UNIT_ADD_WITH_METRIC_PREFIXES(voltage, volt, volts, V, unit<std::ratio<1>, units::category::voltage_unit>)
3757 	UNIT_ADD(voltage, statvolt, statvolts, statV, unit<std::ratio<1000000, 299792458>, volts>)
3758 	UNIT_ADD(voltage, abvolt, abvolts, abV, unit<std::ratio<1, 100000000>, volts>)
3759 
3760 	UNIT_ADD_CATEGORY_TRAIT(voltage)
3761 #endif
3762 
3763 	//------------------------------
3764 	//	UNITS OF CAPACITANCE
3765 	//------------------------------
3766 
3767 	/**
3768 	 * @namespace	units::capacitance
3769 	 * @brief		namespace for unit types and containers representing capacitance values
3770 	 * @details		The SI unit for capacitance is `farads`, and the corresponding `base_unit` category is
3771 	 *				`capacitance_unit`.
3772 	 * @anchor		capacitanceContainers
3773 	 * @sa			See unit_t for more information on unit type containers.
3774 	 */
3775 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_CAPACITANCE_UNITS)
3776 	UNIT_ADD_WITH_METRIC_PREFIXES(capacitance, farad, farads, F, unit<std::ratio<1>, units::category::capacitance_unit>)
3777 
3778 	UNIT_ADD_CATEGORY_TRAIT(capacitance)
3779 #endif
3780 
3781 	//------------------------------
3782 	//	UNITS OF IMPEDANCE
3783 	//------------------------------
3784 
3785 	/**
3786 	 * @namespace	units::impedance
3787 	 * @brief		namespace for unit types and containers representing impedance values
3788 	 * @details		The SI unit for impedance is `ohms`, and the corresponding `base_unit` category is
3789 	 *				`impedance_unit`.
3790 	 * @anchor		impedanceContainers
3791 	 * @sa			See unit_t for more information on unit type containers.
3792 	 */
3793 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_IMPEDANCE_UNITS)
3794 	UNIT_ADD_WITH_METRIC_PREFIXES(impedance, ohm, ohms, Ohm, unit<std::ratio<1>, units::category::impedance_unit>)
3795 
3796 	UNIT_ADD_CATEGORY_TRAIT(impedance)
3797 #endif
3798 
3799 	//------------------------------
3800 	//	UNITS OF CONDUCTANCE
3801 	//------------------------------
3802 
3803 	/**
3804 	 * @namespace	units::conductance
3805 	 * @brief		namespace for unit types and containers representing conductance values
3806 	 * @details		The SI unit for conductance is `siemens`, and the corresponding `base_unit` category is
3807 	 *				`conductance_unit`.
3808 	 * @anchor		conductanceContainers
3809 	 * @sa			See unit_t for more information on unit type containers.
3810 	 */
3811 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_CONDUCTANCE_UNITS)
3812 	UNIT_ADD_WITH_METRIC_PREFIXES(conductance, siemens, siemens, S, unit<std::ratio<1>, units::category::conductance_unit>)
3813 
3814 	UNIT_ADD_CATEGORY_TRAIT(conductance)
3815 #endif
3816 
3817 	//------------------------------
3818 	//	UNITS OF MAGNETIC FLUX
3819 	//------------------------------
3820 
3821 	/**
3822 	 * @namespace	units::magnetic_flux
3823 	 * @brief		namespace for unit types and containers representing magnetic_flux values
3824 	 * @details		The SI unit for magnetic_flux is `webers`, and the corresponding `base_unit` category is
3825 	 *				`magnetic_flux_unit`.
3826 	 * @anchor		magneticFluxContainers
3827 	 * @sa			See unit_t for more information on unit type containers.
3828 	 */
3829 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_MAGNETIC_FLUX_UNITS)
3830 	UNIT_ADD_WITH_METRIC_PREFIXES(magnetic_flux, weber, webers, Wb, unit<std::ratio<1>, units::category::magnetic_flux_unit>)
3831 	UNIT_ADD(magnetic_flux, maxwell, maxwells, Mx, unit<std::ratio<1, 100000000>, webers>)
3832 
3833 	UNIT_ADD_CATEGORY_TRAIT(magnetic_flux)
3834 #endif
3835 
3836 	//----------------------------------------
3837 	//	UNITS OF MAGNETIC FIELD STRENGTH
3838 	//----------------------------------------
3839 
3840 	/**
3841 	 * @namespace	units::magnetic_field_strength
3842 	 * @brief		namespace for unit types and containers representing magnetic_field_strength values
3843 	 * @details		The SI unit for magnetic_field_strength is `teslas`, and the corresponding `base_unit` category is
3844 	 *				`magnetic_field_strength_unit`.
3845 	 * @anchor		magneticFieldStrengthContainers
3846 	 * @sa			See unit_t for more information on unit type containers.
3847 	 */
3848 	// Unfortunately `_T` is a WINAPI macro, so we have to use `_Te` as the tesla abbreviation.
3849 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_MAGNETIC_FIELD_STRENGTH_UNITS)
3850 	UNIT_ADD_WITH_METRIC_PREFIXES(magnetic_field_strength, tesla, teslas, Te, unit<std::ratio<1>, units::category::magnetic_field_strength_unit>)
3851 	UNIT_ADD(magnetic_field_strength, gauss, gauss, G, compound_unit<magnetic_flux::maxwell, inverse<squared<length::centimeter>>>)
3852 
3853 	UNIT_ADD_CATEGORY_TRAIT(magnetic_field_strength)
3854 #endif
3855 
3856 	//------------------------------
3857 	//	UNITS OF INDUCTANCE
3858 	//------------------------------
3859 
3860 	/**
3861 	 * @namespace	units::inductance
3862 	 * @brief		namespace for unit types and containers representing inductance values
3863 	 * @details		The SI unit for inductance is `henrys`, and the corresponding `base_unit` category is
3864 	 *				`inductance_unit`.
3865 	 * @anchor		inductanceContainers
3866 	 * @sa			See unit_t for more information on unit type containers.
3867 	 */
3868 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_INDUCTANCE_UNITS)
3869 	UNIT_ADD_WITH_METRIC_PREFIXES(inductance, henry, henries, H, unit<std::ratio<1>, units::category::inductance_unit>)
3870 
3871 	UNIT_ADD_CATEGORY_TRAIT(inductance)
3872 #endif
3873 
3874 	//------------------------------
3875 	//	UNITS OF LUMINOUS FLUX
3876 	//------------------------------
3877 
3878 	/**
3879 	 * @namespace	units::luminous_flux
3880 	 * @brief		namespace for unit types and containers representing luminous_flux values
3881 	 * @details		The SI unit for luminous_flux is `lumens`, and the corresponding `base_unit` category is
3882 	 *				`luminous_flux_unit`.
3883 	 * @anchor		luminousFluxContainers
3884 	 * @sa			See unit_t for more information on unit type containers.
3885 	 */
3886 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_LUMINOUS_FLUX_UNITS)
3887 	UNIT_ADD_WITH_METRIC_PREFIXES(luminous_flux, lumen, lumens, lm, unit<std::ratio<1>, units::category::luminous_flux_unit>)
3888 
3889 	UNIT_ADD_CATEGORY_TRAIT(luminous_flux)
3890 #endif
3891 
3892 	//------------------------------
3893 	//	UNITS OF ILLUMINANCE
3894 	//------------------------------
3895 
3896 	/**
3897 	 * @namespace	units::illuminance
3898 	 * @brief		namespace for unit types and containers representing illuminance values
3899 	 * @details		The SI unit for illuminance is `luxes`, and the corresponding `base_unit` category is
3900 	 *				`illuminance_unit`.
3901 	 * @anchor		illuminanceContainers
3902 	 * @sa			See unit_t for more information on unit type containers.
3903 	 */
3904 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ILLUMINANCE_UNITS)
3905 	UNIT_ADD_WITH_METRIC_PREFIXES(illuminance, lux, luxes, lx, unit<std::ratio<1>, units::category::illuminance_unit>)
3906 	UNIT_ADD(illuminance, footcandle, footcandles, fc, compound_unit<luminous_flux::lumen, inverse<squared<length::foot>>>)
3907 	UNIT_ADD(illuminance, lumens_per_square_inch, lumens_per_square_inch, lm_per_in_sq, compound_unit<luminous_flux::lumen, inverse<squared<length::inch>>>)
3908 	UNIT_ADD(illuminance, phot, phots, ph, compound_unit<luminous_flux::lumens, inverse<squared<length::centimeter>>>)
3909 
3910 	UNIT_ADD_CATEGORY_TRAIT(illuminance)
3911 #endif
3912 
3913 	//------------------------------
3914 	//	UNITS OF RADIATION
3915 	//------------------------------
3916 
3917 	/**
3918 	 * @namespace	units::radiation
3919 	 * @brief		namespace for unit types and containers representing radiation values
3920 	 * @details		The SI units for radiation are:
3921 	 *				- source activity:	becquerel
3922 	 *				- absorbed dose:	gray
3923 	 *				- equivalent dose:	sievert
3924 	 * @anchor		radiationContainers
3925 	 * @sa			See unit_t for more information on unit type containers.
3926 	 */
3927 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_RADIATION_UNITS)
3928 	UNIT_ADD_WITH_METRIC_PREFIXES(radiation, becquerel, becquerels, Bq, unit<std::ratio<1>, units::frequency::hertz>)
3929 	UNIT_ADD_WITH_METRIC_PREFIXES(radiation, gray, grays, Gy, compound_unit<energy::joules, inverse<mass::kilogram>>)
3930 	UNIT_ADD_WITH_METRIC_PREFIXES(radiation, sievert, sieverts, Sv, unit<std::ratio<1>, grays>)
3931 	UNIT_ADD(radiation, curie, curies, Ci, unit<std::ratio<37>, gigabecquerels>)
3932 	UNIT_ADD(radiation, rutherford, rutherfords, rd, unit<std::ratio<1>, megabecquerels>)
3933 	UNIT_ADD(radiation, rad, rads, rads, unit<std::ratio<1>, centigrays>)
3934 
3935 	UNIT_ADD_CATEGORY_TRAIT(radioactivity)
3936 #endif
3937 
3938 	//------------------------------
3939 	//	UNITS OF TORQUE
3940 	//------------------------------
3941 
3942 	/**
3943 	 * @namespace	units::torque
3944 	 * @brief		namespace for unit types and containers representing torque values
3945 	 * @details		The SI unit for torque is `newton_meters`, and the corresponding `base_unit` category is
3946 	 *				`torque_units`.
3947 	 * @anchor		torqueContainers
3948 	 * @sa			See unit_t for more information on unit type containers.
3949 	 */
3950 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_TORQUE_UNITS)
3951 	UNIT_ADD(torque, newton_meter, newton_meters, Nm, unit<std::ratio<1>, units::energy::joule>)
3952 	UNIT_ADD(torque, foot_pound, foot_pounds, ftlb, compound_unit<length::foot, force::pounds>)
3953 	UNIT_ADD(torque, foot_poundal, foot_poundals, ftpdl, compound_unit<length::foot, force::poundal>)
3954 	UNIT_ADD(torque, inch_pound, inch_pounds, inlb, compound_unit<length::inch, force::pounds>)
3955 	UNIT_ADD(torque, meter_kilogram, meter_kilograms, mkgf, compound_unit<length::meter, force::kiloponds>)
3956 
3957 	UNIT_ADD_CATEGORY_TRAIT(torque)
3958 #endif
3959 
3960 	//------------------------------
3961 	//	AREA UNITS
3962 	//------------------------------
3963 
3964 	/**
3965 	 * @namespace	units::area
3966 	 * @brief		namespace for unit types and containers representing area values
3967 	 * @details		The SI unit for area is `square_meters`, and the corresponding `base_unit` category is
3968 	 *				`area_unit`.
3969 	 * @anchor		areaContainers
3970 	 * @sa			See unit_t for more information on unit type containers.
3971 	 */
3972 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_AREA_UNITS)
3973 	UNIT_ADD(area, square_meter, square_meters, sq_m, unit<std::ratio<1>, units::category::area_unit>)
3974 	UNIT_ADD(area, square_foot, square_feet, sq_ft, squared<length::feet>)
3975 	UNIT_ADD(area, square_inch, square_inches, sq_in, squared<length::inch>)
3976 	UNIT_ADD(area, square_mile, square_miles, sq_mi, squared<length::miles>)
3977 	UNIT_ADD(area, square_kilometer, square_kilometers, sq_km, squared<length::kilometers>)
3978 	UNIT_ADD(area, hectare, hectares, ha, unit<std::ratio<10000>, square_meters>)
3979 	UNIT_ADD(area, acre, acres, acre, unit<std::ratio<43560>, square_feet>)
3980 
3981 	UNIT_ADD_CATEGORY_TRAIT(area)
3982 #endif
3983 
3984 	//------------------------------
3985 	//	UNITS OF VOLUME
3986 	//------------------------------
3987 
3988 	/**
3989 	 * @namespace	units::volume
3990 	 * @brief		namespace for unit types and containers representing volume values
3991 	 * @details		The SI unit for volume is `cubic_meters`, and the corresponding `base_unit` category is
3992 	 *				`volume_unit`.
3993 	 * @anchor		volumeContainers
3994 	 * @sa			See unit_t for more information on unit type containers.
3995 	 */
3996 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_VOLUME_UNITS)
3997 	UNIT_ADD(volume, cubic_meter, cubic_meters, cu_m, unit<std::ratio<1>, units::category::volume_unit>)
3998 	UNIT_ADD(volume, cubic_millimeter, cubic_millimeters, cu_mm, cubed<length::millimeter>)
3999 	UNIT_ADD(volume, cubic_kilometer, cubic_kilometers, cu_km, cubed<length::kilometer>)
4000 	UNIT_ADD_WITH_METRIC_PREFIXES(volume, liter, liters, L, cubed<deci<length::meter>>)
4001 	UNIT_ADD(volume, cubic_inch, cubic_inches, cu_in, cubed<length::inches>)
4002 	UNIT_ADD(volume, cubic_foot, cubic_feet, cu_ft, cubed<length::feet>)
4003 	UNIT_ADD(volume, cubic_yard, cubic_yards, cu_yd, cubed<length::yards>)
4004 	UNIT_ADD(volume, cubic_mile, cubic_miles, cu_mi, cubed<length::miles>)
4005 	UNIT_ADD(volume, gallon, gallons, gal, unit<std::ratio<231>, cubic_inches>)
4006 	UNIT_ADD(volume, quart, quarts, qt, unit<std::ratio<1, 4>, gallons>)
4007 	UNIT_ADD(volume, pint, pints, pt, unit<std::ratio<1, 2>, quarts>)
4008 	UNIT_ADD(volume, cup, cups, c, unit<std::ratio<1, 2>, pints>)
4009 	UNIT_ADD(volume, fluid_ounce, fluid_ounces, fl_oz, unit<std::ratio<1, 8>, cups>)
4010 	UNIT_ADD(volume, barrel, barrels, bl, unit<std::ratio<42>, gallons>)
4011 	UNIT_ADD(volume, bushel, bushels, bu, unit<std::ratio<215042, 100>, cubic_inches>)
4012 	UNIT_ADD(volume, cord, cords, cord, unit<std::ratio<128>, cubic_feet>)
4013 	UNIT_ADD(volume, cubic_fathom, cubic_fathoms, cu_fm, cubed<length::fathom>)
4014 	UNIT_ADD(volume, tablespoon, tablespoons, tbsp, unit<std::ratio<1, 2>, fluid_ounces>)
4015 	UNIT_ADD(volume, teaspoon, teaspoons, tsp, unit<std::ratio<1, 6>, fluid_ounces>)
4016 	UNIT_ADD(volume, pinch, pinches, pinch, unit<std::ratio<1, 8>, teaspoons>)
4017 	UNIT_ADD(volume, dash, dashes, dash, unit<std::ratio<1, 2>, pinches>)
4018 	UNIT_ADD(volume, drop, drops, drop, unit<std::ratio<1, 360>, fluid_ounces>)
4019 	UNIT_ADD(volume, fifth, fifths, fifth, unit<std::ratio<1, 5>, gallons>)
4020 	UNIT_ADD(volume, dram, drams, dr, unit<std::ratio<1, 8>, fluid_ounces>)
4021 	UNIT_ADD(volume, gill, gills, gi, unit<std::ratio<4>, fluid_ounces>)
4022 	UNIT_ADD(volume, peck, pecks, pk, unit<std::ratio<1, 4>, bushels>)
4023 	UNIT_ADD(volume, sack, sacks, sacks, unit<std::ratio<3>, bushels>)
4024 	UNIT_ADD(volume, shot, shots, shots, unit<std::ratio<3, 2>, fluid_ounces>)
4025 	UNIT_ADD(volume, strike, strikes, strikes, unit<std::ratio<2>, bushels>)
4026 
4027 	UNIT_ADD_CATEGORY_TRAIT(volume)
4028 #endif
4029 
4030 	//------------------------------
4031 	//	UNITS OF DENSITY
4032 	//------------------------------
4033 
4034 	/**
4035 	 * @namespace	units::density
4036 	 * @brief		namespace for unit types and containers representing density values
4037 	 * @details		The SI unit for density is `kilograms_per_cubic_meter`, and the corresponding `base_unit` category is
4038 	 *				`density_unit`.
4039 	 * @anchor		densityContainers
4040 	 * @sa			See unit_t for more information on unit type containers.
4041 	 */
4042 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_DENSITY_UNITS)
4043 	UNIT_ADD(density, kilograms_per_cubic_meter, kilograms_per_cubic_meter, kg_per_cu_m, unit<std::ratio<1>, units::category::density_unit>)
4044 	UNIT_ADD(density, grams_per_milliliter, grams_per_milliliter, g_per_mL, compound_unit<mass::grams, inverse<volume::milliliter>>)
4045 	UNIT_ADD(density, kilograms_per_liter, kilograms_per_liter, kg_per_L, unit<std::ratio<1>, compound_unit<mass::grams, inverse<volume::milliliter>>>)
4046 	UNIT_ADD(density, ounces_per_cubic_foot, ounces_per_cubic_foot, oz_per_cu_ft, compound_unit<mass::ounces, inverse<volume::cubic_foot>>)
4047 	UNIT_ADD(density, ounces_per_cubic_inch, ounces_per_cubic_inch, oz_per_cu_in, compound_unit<mass::ounces, inverse<volume::cubic_inch>>)
4048 	UNIT_ADD(density, ounces_per_gallon, ounces_per_gallon, oz_per_gal, compound_unit<mass::ounces, inverse<volume::gallon>>)
4049 	UNIT_ADD(density, pounds_per_cubic_foot, pounds_per_cubic_foot, lb_per_cu_ft, compound_unit<mass::pounds, inverse<volume::cubic_foot>>)
4050 	UNIT_ADD(density, pounds_per_cubic_inch, pounds_per_cubic_inch, lb_per_cu_in, compound_unit<mass::pounds, inverse<volume::cubic_inch>>)
4051 	UNIT_ADD(density, pounds_per_gallon, pounds_per_gallon, lb_per_gal, compound_unit<mass::pounds, inverse<volume::gallon>>)
4052 	UNIT_ADD(density, slugs_per_cubic_foot, slugs_per_cubic_foot, slug_per_cu_ft, compound_unit<mass::slugs, inverse<volume::cubic_foot>>)
4053 
4054 	UNIT_ADD_CATEGORY_TRAIT(density)
4055 #endif
4056 
4057 	//------------------------------
4058 	//	UNITS OF CONCENTRATION
4059 	//------------------------------
4060 
4061 	/**
4062 	 * @namespace	units::concentration
4063 	 * @brief		namespace for unit types and containers representing concentration values
4064 	 * @details		The SI unit for concentration is `parts_per_million`, and the corresponding `base_unit` category is
4065 	 *				`scalar_unit`.
4066 	 * @anchor		concentrationContainers
4067 	 * @sa			See unit_t for more information on unit type containers.
4068 	 */
4069 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_CONCENTRATION_UNITS)
4070 	UNIT_ADD(concentration, ppm, parts_per_million, ppm, unit<std::ratio<1, 1000000>, units::category::scalar_unit>)
4071 	UNIT_ADD(concentration, ppb, parts_per_billion, ppb, unit<std::ratio<1, 1000>, parts_per_million>)
4072 	UNIT_ADD(concentration, ppt, parts_per_trillion, ppt, unit<std::ratio<1, 1000>, parts_per_billion>)
4073 	UNIT_ADD(concentration, percent, percent, pct, unit<std::ratio<1, 100>, units::category::scalar_unit>)
4074 
4075 	UNIT_ADD_CATEGORY_TRAIT(concentration)
4076 #endif
4077 
4078 	//------------------------------
4079 	//	UNITS OF DATA
4080 	//------------------------------
4081 
4082 	/**
4083 	 * @namespace	units::data
4084 	 * @brief		namespace for unit types and containers representing data values
4085 	 * @details		The base unit for data is `bytes`, and the corresponding `base_unit` category is
4086 	 *				`data_unit`.
4087 	 * @anchor		dataContainers
4088 	 * @sa			See unit_t for more information on unit type containers.
4089 	 */
4090 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_DATA_UNITS)
4091 	UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(data, byte, bytes, B, unit<std::ratio<1>, units::category::data_unit>)
4092 	UNIT_ADD(data, exabyte, exabytes, EB, unit<std::ratio<1000>, petabytes>)
4093 	UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(data, bit, bits, b, unit<std::ratio<1, 8>, byte>)
4094 	UNIT_ADD(data, exabit, exabits, Eb, unit<std::ratio<1000>, petabits>)
4095 
4096 	UNIT_ADD_CATEGORY_TRAIT(data)
4097 #endif
4098 
4099 	//------------------------------
4100 	//	UNITS OF DATA TRANSFER
4101 	//------------------------------
4102 
4103 	/**
4104 	* @namespace	units::data_transfer_rate
4105 	* @brief		namespace for unit types and containers representing data values
4106 	* @details		The base unit for data is `bytes`, and the corresponding `base_unit` category is
4107 	*				`data_unit`.
4108 	* @anchor		dataContainers
4109 	* @sa			See unit_t for more information on unit type containers.
4110 	*/
4111 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_DATA_TRANSFER_RATE_UNITS)
4112 	UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(data_transfer_rate, bytes_per_second, bytes_per_second, Bps, unit<std::ratio<1>, units::category::data_transfer_rate_unit>)
4113 	UNIT_ADD(data_transfer_rate, exabytes_per_second, exabytes_per_second, EBps, unit<std::ratio<1000>, petabytes_per_second>)
4114 	UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(data_transfer_rate, bits_per_second, bits_per_second, bps, unit<std::ratio<1, 8>, bytes_per_second>)
4115 	UNIT_ADD(data_transfer_rate, exabits_per_second, exabits_per_second, Ebps, unit<std::ratio<1000>, petabits_per_second>)
4116 
4117 	UNIT_ADD_CATEGORY_TRAIT(data_transfer_rate)
4118 #endif
4119 
4120 	//------------------------------
4121 	//	CONSTANTS
4122 	//------------------------------
4123 
4124 	/**
4125 	 * @brief		namespace for physical constants like PI and Avogadro's Number.
4126 	 * @sa			See unit_t for more information on unit type containers.
4127 	 */
4128 #if !defined(DISABLE_PREDEFINED_UNITS)
4129 	namespace constants
4130 	{
4131 		/**
4132 		 * @name Unit Containers
4133 		 * @anchor constantContainers
4134 		 * @{
4135 		 */
4136 		using PI = unit<std::ratio<1>, dimensionless::scalar, std::ratio<1>>;
4137 
4138 		static constexpr const unit_t<PI>																											pi(1);											///< Ratio of a circle's circumference to its diameter.
4139 		static constexpr const velocity::meters_per_second_t																						c(299792458.0);									///< Speed of light in vacuum.
4140 		static constexpr const unit_t<compound_unit<cubed<length::meters>, inverse<mass::kilogram>, inverse<squared<time::seconds>>>>				G(6.67408e-11);									///< Newtonian constant of gravitation.
4141 		static constexpr const unit_t<compound_unit<energy::joule, time::seconds>>																	h(6.626070040e-34);								///< Planck constant.
4142 		static constexpr const unit_t<compound_unit<force::newtons, inverse<squared<current::ampere>>>>												mu0(pi * 4.0e-7 * force::newton_t(1) / units::math::cpow<2>(current::ampere_t(1)));										///< vacuum permeability.
4143 		static constexpr const unit_t<compound_unit<capacitance::farad, inverse<length::meter>>>													epsilon0(1.0 / (mu0 * math::cpow<2>(c)));		///< vacuum permitivity.
4144 		static constexpr const impedance::ohm_t																										Z0(mu0 * c);									///< characteristic impedance of vacuum.
4145 		static constexpr const unit_t<compound_unit<force::newtons, area::square_meter, inverse<squared<charge::coulomb>>>>							k_e(1.0 / (4 * pi * epsilon0));					///< Coulomb's constant.
4146 		static constexpr const charge::coulomb_t																									e(1.6021766208e-19);							///< elementary charge.
4147 		static constexpr const mass::kilogram_t																										m_e(9.10938356e-31);							///< electron mass.
4148 		static constexpr const mass::kilogram_t																										m_p(1.672621898e-27);							///< proton mass.
4149 		static constexpr const unit_t<compound_unit<energy::joules, inverse<magnetic_field_strength::tesla>>>										mu_B(e * h / (4 * pi *m_e));					///< Bohr magneton.
4150 		static constexpr const unit_t<inverse<substance::mol>>																						N_A(6.022140857e23);							///< Avagadro's Number.
4151 		static constexpr const unit_t<compound_unit<energy::joules, inverse<temperature::kelvin>, inverse<substance::moles>>>						R(8.3144598);									///< Gas constant.
4152 		static constexpr const unit_t<compound_unit<energy::joules, inverse<temperature::kelvin>>>													k_B(R / N_A);									///< Boltzmann constant.
4153 		static constexpr const unit_t<compound_unit<charge::coulomb, inverse<substance::mol>>>														F(N_A * e);										///< Faraday constant.
4154 		static constexpr const unit_t<compound_unit<power::watts, inverse<area::square_meters>, inverse<squared<squared<temperature::kelvin>>>>>	sigma((2 * math::cpow<5>(pi) * math::cpow<4>(R)) / (15 * math::cpow<3>(h) * math::cpow<2>(c) * math::cpow<4>(N_A)));	///< Stefan-Boltzmann constant.
4155 		/** @} */
4156 	}
4157 #endif
4158 
4159 	//----------------------------------
4160 	//	UNIT-ENABLED CMATH FUNCTIONS
4161 	//----------------------------------
4162 
4163 	/**
4164 	 * @brief		namespace for unit-enabled versions of the `<cmath>` library
4165 	 * @details		Includes trigonometric functions, exponential/log functions, rounding functions, etc.
4166 	 * @sa			See `unit_t` for more information on unit type containers.
4167 	 */
4168 	namespace math
4169 	{
4170 
4171 		//----------------------------------
4172 		//	MIN/MAX FUNCTIONS
4173 		//----------------------------------
4174 
4175 		template<class UnitTypeLhs, class UnitTypeRhs>
4176 		UnitTypeLhs min(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs)
4177 		{
4178 			static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Unit types are not compatible.");
4179 			UnitTypeLhs r(rhs);
4180 			return (lhs < r ? lhs : r);
4181 		}
4182 
4183 		template<class UnitTypeLhs, class UnitTypeRhs>
4184 		UnitTypeLhs max(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs)
4185 		{
4186 			static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Unit types are not compatible.");
4187 			UnitTypeLhs r(rhs);
4188 			return (lhs > r ? lhs : r);
4189 		}
4190 
4191 		//----------------------------------
4192 		//	TRIGONOMETRIC FUNCTIONS
4193 		//----------------------------------
4194 
4195 		/**
4196 		 * @ingroup		UnitMath
4197 		 * @brief		Compute cosine
4198 		 * @details		The input value can be in any unit of angle, including radians or degrees.
4199 		 * @tparam		AngleUnit	any `unit_t` type of `category::angle_unit`.
4200 		 * @param[in]	angle		angle to compute the cosine of
4201 		 * @returns		Returns the cosine of <i>angle</i>
4202 		 */
4203 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
4204 		template<class AngleUnit>
cos(const AngleUnit angle)4205 		dimensionless::scalar_t cos(const AngleUnit angle) noexcept
4206 		{
4207 			static_assert(traits::is_angle_unit<AngleUnit>::value, "Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
4208 			return dimensionless::scalar_t(std::cos(angle.template convert<angle::radian>()()));
4209 		}
4210 #endif
4211 
4212 		/**
4213 		 * @ingroup		UnitMath
4214 		 * @brief		Compute sine
4215 		 * @details		The input value can be in any unit of angle, including radians or degrees.
4216 		 * @tparam		AngleUnit	any `unit_t` type of `category::angle_unit`.
4217 		 * @param[in]	angle		angle to compute the since of
4218 		 * @returns		Returns the sine of <i>angle</i>
4219 		 */
4220 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
4221 		template<class AngleUnit>
sin(const AngleUnit angle)4222 		dimensionless::scalar_t sin(const AngleUnit angle) noexcept
4223 		{
4224 			static_assert(traits::is_angle_unit<AngleUnit>::value, "Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
4225 			return dimensionless::scalar_t(std::sin(angle.template convert<angle::radian>()()));
4226 		}
4227 #endif
4228 		/**
4229 		 * @ingroup		UnitMath
4230 		 * @brief		Compute tangent
4231 		 * @details		The input value can be in any unit of angle, including radians or degrees.
4232 		 * @tparam		AngleUnit	any `unit_t` type of `category::angle_unit`.
4233 		 * @param[in]	angle		angle to compute the tangent of
4234 		 * @returns		Returns the tangent of <i>angle</i>
4235 		 */
4236 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
4237 		template<class AngleUnit>
tan(const AngleUnit angle)4238 		dimensionless::scalar_t tan(const AngleUnit angle) noexcept
4239 		{
4240 			static_assert(traits::is_angle_unit<AngleUnit>::value, "Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
4241 			return dimensionless::scalar_t(std::tan(angle.template convert<angle::radian>()()));
4242 		}
4243 #endif
4244 
4245 		/**
4246 		 * @ingroup		UnitMath
4247 		 * @brief		Compute arc cosine
4248 		 * @details		Returns the principal value of the arc cosine of x, expressed in radians.
4249 		 * @param[in]	x		Value whose arc cosine is computed, in the interval [-1,+1].
4250 		 * @returns		Principal arc cosine of x, in the interval [0,pi] radians.
4251 		 */
4252 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
4253 		template<class ScalarUnit>
acos(const ScalarUnit x)4254 		angle::radian_t acos(const ScalarUnit x) noexcept
4255 		{
4256 			static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
4257 			return angle::radian_t(std::acos(x()));
4258 		}
4259 #endif
4260 
4261 		/**
4262 		 * @ingroup		UnitMath
4263 		 * @brief		Compute arc sine
4264 		 * @details		Returns the principal value of the arc sine of x, expressed in radians.
4265 		 * @param[in]	x		Value whose arc sine is computed, in the interval [-1,+1].
4266 		 * @returns		Principal arc sine of x, in the interval [-pi/2,+pi/2] radians.
4267 		 */
4268 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
4269 		template<class ScalarUnit>
asin(const ScalarUnit x)4270 		angle::radian_t asin(const ScalarUnit x) noexcept
4271 		{
4272 			static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
4273 			return angle::radian_t(std::asin(x()));
4274 		}
4275 #endif
4276 
4277 		/**
4278 		 * @ingroup		UnitMath
4279 		 * @brief		Compute arc tangent
4280 		 * @details		Returns the principal value of the arc tangent of x, expressed in radians.
4281 		 *				Notice that because of the sign ambiguity, the function cannot determine with
4282 		 *				certainty in which quadrant the angle falls only by its tangent value. See
4283 		 *				atan2 for an alternative that takes a fractional argument instead.
4284 		 * @tparam		AngleUnit	any `unit_t` type of `category::angle_unit`.
4285 		 * @param[in]	x		Value whose arc tangent is computed, in the interval [-1,+1].
4286 		 * @returns		Principal arc tangent of x, in the interval [-pi/2,+pi/2] radians.
4287 		 */
4288 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
4289 		template<class ScalarUnit>
atan(const ScalarUnit x)4290 		angle::radian_t atan(const ScalarUnit x) noexcept
4291 		{
4292 			static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
4293 			return angle::radian_t(std::atan(x()));
4294 		}
4295 #endif
4296 
4297 		/**
4298 		 * @ingroup		UnitMath
4299 		 * @brief		Compute arc tangent with two parameters
4300 		 * @details		To compute the value, the function takes into account the sign of both arguments in order to determine the quadrant.
4301 		 * @param[in]	y		y-component of the triangle expressed.
4302 		 * @param[in]	x		x-component of the triangle expressed.
4303 		 * @returns		Returns the principal value of the arc tangent of <i>y/x</i>, expressed in radians.
4304 		 */
4305 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
4306 		template<class Y, class X>
atan2(const Y y,const X x)4307 		angle::radian_t atan2(const Y y, const X x) noexcept
4308 		{
4309 			static_assert(traits::is_dimensionless_unit<decltype(y/x)>::value, "The quantity y/x must yield a dimensionless ratio.");
4310 
4311 			// X and Y could be different length units, so normalize them
4312 			return angle::radian_t(std::atan2(y.template convert<typename units::traits::unit_t_traits<X>::unit_type>()(), x()));
4313 		}
4314 #endif
4315 
4316 		//----------------------------------
4317 		//	HYPERBOLIC TRIG FUNCTIONS
4318 		//----------------------------------
4319 
4320 		/**
4321 		 * @ingroup		UnitMath
4322 		 * @brief		Compute hyperbolic cosine
4323 		 * @details		The input value can be in any unit of angle, including radians or degrees.
4324 		 * @tparam		AngleUnit	any `unit_t` type of `category::angle_unit`.
4325 		 * @param[in]	angle		angle to compute the hyperbolic cosine of
4326 		 * @returns		Returns the hyperbolic cosine of <i>angle</i>
4327 		 */
4328 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
4329 		template<class AngleUnit>
cosh(const AngleUnit angle)4330 		dimensionless::scalar_t cosh(const AngleUnit angle) noexcept
4331 		{
4332 			static_assert(traits::is_angle_unit<AngleUnit>::value, "Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
4333 			return dimensionless::scalar_t(std::cosh(angle.template convert<angle::radian>()()));
4334 		}
4335 #endif
4336 
4337 		/**
4338 		* @ingroup		UnitMath
4339 		* @brief		Compute hyperbolic sine
4340 		* @details		The input value can be in any unit of angle, including radians or degrees.
4341 		* @tparam		AngleUnit	any `unit_t` type of `category::angle_unit`.
4342 		* @param[in]	angle		angle to compute the hyperbolic sine of
4343 		* @returns		Returns the hyperbolic sine of <i>angle</i>
4344 		*/
4345 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
4346 		template<class AngleUnit>
sinh(const AngleUnit angle)4347 		dimensionless::scalar_t sinh(const AngleUnit angle) noexcept
4348 		{
4349 			static_assert(traits::is_angle_unit<AngleUnit>::value, "Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
4350 			return dimensionless::scalar_t(std::sinh(angle.template convert<angle::radian>()()));
4351 		}
4352 #endif
4353 
4354 		/**
4355 		* @ingroup		UnitMath
4356 		* @brief		Compute hyperbolic tangent
4357 		* @details		The input value can be in any unit of angle, including radians or degrees.
4358 		* @tparam		AngleUnit	any `unit_t` type of `category::angle_unit`.
4359 		* @param[in]	angle		angle to compute the hyperbolic tangent of
4360 		* @returns		Returns the hyperbolic tangent of <i>angle</i>
4361 		*/
4362 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
4363 		template<class AngleUnit>
tanh(const AngleUnit angle)4364 		dimensionless::scalar_t tanh(const AngleUnit angle) noexcept
4365 		{
4366 			static_assert(traits::is_angle_unit<AngleUnit>::value, "Type `AngleUnit` must be a unit of angle derived from `unit_t`.");
4367 			return dimensionless::scalar_t(std::tanh(angle.template convert<angle::radian>()()));
4368 		}
4369 #endif
4370 
4371 		/**
4372 		 * @ingroup		UnitMath
4373 		 * @brief		Compute arc hyperbolic cosine
4374 		 * @details		Returns the nonnegative arc hyperbolic cosine of x, expressed in radians.
4375 		 * @param[in]	x	Value whose arc hyperbolic cosine is computed. If the argument is less
4376 		 *					than 1, a domain error occurs.
4377 		 * @returns		Nonnegative arc hyperbolic cosine of x, in the interval [0,+INFINITY] radians.
4378 		 */
4379 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
4380 		template<class ScalarUnit>
acosh(const ScalarUnit x)4381 		angle::radian_t acosh(const ScalarUnit x) noexcept
4382 		{
4383 			static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
4384 			return angle::radian_t(std::acosh(x()));
4385 		}
4386 #endif
4387 
4388 		/**
4389 		 * @ingroup		UnitMath
4390 		 * @brief		Compute arc hyperbolic sine
4391 		 * @details		Returns the arc hyperbolic sine of x, expressed in radians.
4392 		 * @param[in]	x	Value whose arc hyperbolic sine is computed.
4393 		 * @returns		Arc hyperbolic sine of x, in radians.
4394 		 */
4395 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
4396 		template<class ScalarUnit>
asinh(const ScalarUnit x)4397 		angle::radian_t asinh(const ScalarUnit x) noexcept
4398 		{
4399 			static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
4400 			return angle::radian_t(std::asinh(x()));
4401 		}
4402 #endif
4403 
4404 		/**
4405 		 * @ingroup		UnitMath
4406 		 * @brief		Compute arc hyperbolic tangent
4407 		 * @details		Returns the arc hyperbolic tangent of x, expressed in radians.
4408 		 * @param[in]	x	Value whose arc hyperbolic tangent is computed, in the interval [-1,+1].
4409 		 *					If the argument is out of this interval, a domain error occurs. For
4410 		 *					values of -1 and +1, a pole error may occur.
4411 		 * @returns		units::angle::radian_t
4412 		 */
4413 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS)
4414 		template<class ScalarUnit>
atanh(const ScalarUnit x)4415 		angle::radian_t atanh(const ScalarUnit x) noexcept
4416 		{
4417 			static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
4418 			return angle::radian_t(std::atanh(x()));
4419 		}
4420 #endif
4421 
4422 		//----------------------------------
4423 		//	TRANSCENDENTAL FUNCTIONS
4424 		//----------------------------------
4425 
4426 		// it makes NO SENSE to put dimensioned units into a transcendental function, and if you think it does you are
4427 		// demonstrably wrong. https://en.wikipedia.org/wiki/Transcendental_function#Dimensional_analysis
4428 
4429 		/**
4430 		 * @ingroup		UnitMath
4431 		 * @brief		Compute exponential function
4432 		 * @details		Returns the base-e exponential function of x, which is e raised to the power x: ex.
4433 		 * @param[in]	x	scalar value of the exponent.
4434 		 * @returns		Exponential value of x.
4435 		 *				If the magnitude of the result is too large to be represented by a value of the return type, the
4436 		 *				function returns HUGE_VAL (or HUGE_VALF or HUGE_VALL) with the proper sign, and an overflow range error occurs
4437 		 */
4438 		template<class ScalarUnit>
exp(const ScalarUnit x)4439 		dimensionless::scalar_t exp(const ScalarUnit x) noexcept
4440 		{
4441 			static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
4442 			return dimensionless::scalar_t(std::exp(x()));
4443 		}
4444 
4445 		/**
4446 		 * @ingroup		UnitMath
4447 		 * @brief		Compute natural logarithm
4448 		 * @details		Returns the natural logarithm of x.
4449 		 * @param[in]	x	scalar value whose logarithm is calculated. If the argument is negative, a
4450 		 *					domain error occurs.
4451 		 * @sa			log10 for more common base-10 logarithms
4452 		 * @returns		Natural logarithm of x.
4453 		 */
4454 		template<class ScalarUnit>
log(const ScalarUnit x)4455 		dimensionless::scalar_t log(const ScalarUnit x) noexcept
4456 		{
4457 			static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
4458 			return dimensionless::scalar_t(std::log(x()));
4459 		}
4460 
4461 		/**
4462 		 * @ingroup		UnitMath
4463 		 * @brief		Compute common logarithm
4464 		 * @details		Returns the common (base-10) logarithm of x.
4465 		 * @param[in]	x	Value whose logarithm is calculated. If the argument is negative, a
4466 		 *					domain error occurs.
4467 		 * @returns		Common logarithm of x.
4468 		 */
4469 		template<class ScalarUnit>
log10(const ScalarUnit x)4470 		dimensionless::scalar_t log10(const ScalarUnit x) noexcept
4471 		{
4472 			static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
4473 			return dimensionless::scalar_t(std::log10(x()));
4474 		}
4475 
4476 		/**
4477 		 * @ingroup		UnitMath
4478 		 * @brief		Break into fractional and integral parts.
4479 		 * @details		The integer part is stored in the object pointed by intpart, and the
4480 		 *				fractional part is returned by the function. Both parts have the same sign
4481 		 *				as x.
4482 		 * @param[in]	x		scalar value to break into parts.
4483 		 * @param[in]	intpart Pointer to an object (of the same type as x) where the integral part
4484 		 *				is stored with the same sign as x.
4485 		 * @returns		The fractional part of x, with the same sign.
4486 		 */
4487 		template<class ScalarUnit>
modf(const ScalarUnit x,ScalarUnit * intpart)4488 		dimensionless::scalar_t modf(const ScalarUnit x, ScalarUnit* intpart) noexcept
4489 		{
4490 			static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
4491 
4492 			UNIT_LIB_DEFAULT_TYPE intp;
4493 			dimensionless::scalar_t fracpart = dimensionless::scalar_t(std::modf(x(), &intp));
4494 			*intpart = intp;
4495 			return fracpart;
4496 		}
4497 
4498 		/**
4499 		 * @ingroup		UnitMath
4500 		 * @brief		Compute binary exponential function
4501 		 * @details		Returns the base-2 exponential function of x, which is 2 raised to the power x: 2^x.
4502 		 * 2param[in]	x	Value of the exponent.
4503 		 * @returns		2 raised to the power of x.
4504 		 */
4505 		template<class ScalarUnit>
exp2(const ScalarUnit x)4506 		dimensionless::scalar_t exp2(const ScalarUnit x) noexcept
4507 		{
4508 			static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
4509 			return dimensionless::scalar_t(std::exp2(x()));
4510 		}
4511 
4512 		/**
4513 		 * @ingroup		UnitMath
4514 		 * @brief		Compute exponential minus one
4515 		 * @details		Returns e raised to the power x minus one: e^x-1. For small magnitude values
4516 		 *				of x, expm1 may be more accurate than exp(x)-1.
4517 		 * @param[in]	x	Value of the exponent.
4518 		 * @returns		e raised to the power of x, minus one.
4519 		 */
4520 		template<class ScalarUnit>
expm1(const ScalarUnit x)4521 		dimensionless::scalar_t expm1(const ScalarUnit x) noexcept
4522 		{
4523 			static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
4524 			return dimensionless::scalar_t(std::expm1(x()));
4525 		}
4526 
4527 		/**
4528 		 * @ingroup		UnitMath
4529 		 * @brief		Compute logarithm plus one
4530 		 * @details		Returns the natural logarithm of one plus x. For small magnitude values of
4531 		 *				x, logp1 may be more accurate than log(1+x).
4532 		 * @param[in]	x	Value whose logarithm is calculated. If the argument is less than -1, a
4533 		 *					domain error occurs.
4534 		 * @returns		The natural logarithm of (1+x).
4535 		 */
4536 		template<class ScalarUnit>
log1p(const ScalarUnit x)4537 		dimensionless::scalar_t log1p(const ScalarUnit x) noexcept
4538 		{
4539 			static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
4540 			return dimensionless::scalar_t(std::log1p(x()));
4541 		}
4542 
4543 		/**
4544 		 * @ingroup		UnitMath
4545 		 * @brief		Compute binary logarithm
4546 		 * @details		Returns the binary (base-2) logarithm of x.
4547 		 * @param[in]	x	Value whose logarithm is calculated. If the argument is negative, a
4548 		 *					domain error occurs.
4549 		 * @returns		The binary logarithm of x: log2x.
4550 		 */
4551 		template<class ScalarUnit>
log2(const ScalarUnit x)4552 		dimensionless::scalar_t log2(const ScalarUnit x) noexcept
4553 		{
4554 			static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`.");
4555 			return dimensionless::scalar_t(std::log2(x()));
4556 		}
4557 
4558 		//----------------------------------
4559 		//	POWER FUNCTIONS
4560 		//----------------------------------
4561 
4562 		/* pow is implemented earlier in the library since a lot of the unit definitions depend on it */
4563 
4564 		/**
4565 		 * @ingroup		UnitMath
4566 		 * @brief		computes the square root of <i>value</i>
4567 		 * @details		Only implemented for linear_scale units.
4568 		 * @param[in]	value `unit_t` derived type to compute the square root of.
4569 		 * @returns		new unit_t, whose units are the square root of value's. E.g. if values
4570 		 *				had units of `square_meter`, then the return type will have units of
4571 		 *				`meter`.
4572 		 * @note		`sqrt` provides a _rational approximation_ of the square root of <i>value</i>.
4573 		 *				In some cases, _both_ the returned value _and_ conversion factor of the returned
4574 		 *				unit type may have errors no larger than `1e-10`.
4575 		 */
4576 		template<class UnitType, std::enable_if_t<units::traits::has_linear_scale<UnitType>::value, int> = 0>
sqrt(const UnitType & value)4577 		inline auto sqrt(const UnitType& value) noexcept -> unit_t<square_root<typename units::traits::unit_t_traits<UnitType>::unit_type>, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
4578 		{
4579 			return unit_t<square_root<typename units::traits::unit_t_traits<UnitType>::unit_type>, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
4580 				(std::sqrt(value()));
4581 		}
4582 
4583 		/**
4584 		 * @ingroup		UnitMath
4585 		 * @brief		Computes the square root of the sum-of-squares of x and y.
4586 		 * @details		Only implemented for linear_scale units.
4587 		 * @param[in]	x	unit_t type value
4588 		 * @param[in]	y	unit_t type value
4589 		 * @returns		square root of the sum-of-squares of x and y in the same units
4590 		 *				as x.
4591 		 */
4592 		template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<units::traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
hypot(const UnitTypeLhs & x,const UnitTypeRhs & y)4593 		inline UnitTypeLhs hypot(const UnitTypeLhs& x, const UnitTypeRhs& y)
4594 		{
4595 			static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Parameters of hypot() function are not compatible units.");
4596 			return UnitTypeLhs(std::hypot(x(), y.template convert<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()()));
4597 		}
4598 
4599 		//----------------------------------
4600 		//	ROUNDING FUNCTIONS
4601 		//----------------------------------
4602 
4603 		/**
4604 		 * @ingroup		UnitMath
4605 		 * @brief		Round up value
4606 		 * @details		Rounds x upward, returning the smallest integral value that is not less than x.
4607 		 * @param[in]	x	Unit value to round up.
4608 		 * @returns		The smallest integral value that is not less than x.
4609 		 */
4610 		template<class UnitType, class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
4611 		UnitType ceil(const UnitType x) noexcept
4612 		{
4613 			return UnitType(std::ceil(x()));
4614 		}
4615 
4616 		/**
4617 		 * @ingroup		UnitMath
4618 		 * @brief		Round down value
4619 		 * @details		Rounds x downward, returning the largest integral value that is not greater than x.
4620 		 * @param[in]	x	Unit value to round down.
4621 		 * @returns		The value of x rounded downward.
4622 		 */
4623 		template<class UnitType, class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
4624 		UnitType floor(const UnitType x) noexcept
4625 		{
4626 			return UnitType(std::floor(x()));
4627 		}
4628 
4629 		/**
4630 		 * @ingroup		UnitMath
4631 		 * @brief		Compute remainder of division
4632 		 * @details		Returns the floating-point remainder of numer/denom (rounded towards zero).
4633 		 * @param[in]	numer	Value of the quotient numerator.
4634 		 * @param[in]	denom	Value of the quotient denominator.
4635 		 * @returns		The remainder of dividing the arguments.
4636 		 */
4637 		template<class UnitTypeLhs, class UnitTypeRhs, class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value && traits::is_unit_t<UnitTypeRhs>::value>>
4638 		UnitTypeLhs fmod(const UnitTypeLhs numer, const UnitTypeRhs denom) noexcept
4639 		{
4640 			static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Parameters of fmod() function are not compatible units.");
4641 			return UnitTypeLhs(std::fmod(numer(), denom.template convert<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()()));
4642 		}
4643 
4644 		/**
4645 		 * @ingroup		UnitMath
4646 		 * @brief		Truncate value
4647 		 * @details		Rounds x toward zero, returning the nearest integral value that is not
4648 		 *				larger in magnitude than x. Effectively rounds towards 0.
4649 		 * @param[in]	x	Value to truncate
4650 		 * @returns		The nearest integral value that is not larger in magnitude than x.
4651 		 */
4652 		template<class UnitType, class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
4653 		UnitType trunc(const UnitType x) noexcept
4654 		{
4655 			return UnitType(std::trunc(x()));
4656 		}
4657 
4658 
4659 		/**
4660 		 * @ingroup		UnitMath
4661 		 * @brief		Round to nearest
4662 		 * @details		Returns the integral value that is nearest to x, with halfway cases rounded
4663 		 *				away from zero.
4664 		 * @param[in]	x	value to round.
4665 		 * @returns		The value of x rounded to the nearest integral.
4666 		 */
4667 		template<class UnitType, class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
4668 		UnitType round(const UnitType x) noexcept
4669 		{
4670 			return UnitType(std::round(x()));
4671 		}
4672 
4673 		//----------------------------------
4674 		//	FLOATING POINT MANIPULATION
4675 		//----------------------------------
4676 
4677 		/**
4678 		 * @ingroup		UnitMath
4679 		 * @brief		Copy sign
4680 		 * @details		Returns a value with the magnitude and dimension of x, and the sign of y.
4681 		 *				Values x and y do not have to be compatible units.
4682 		 * @param[in]	x	Value with the magnitude of the resulting value.
4683 		 * @param[in]	y	Value with the sign of the resulting value.
4684 		 * @returns		value with the magnitude and dimension of x, and the sign of y.
4685 		 */
4686 		template<class UnitTypeLhs, class UnitTypeRhs, class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value && traits::is_unit_t<UnitTypeRhs>::value>>
4687 		UnitTypeLhs copysign(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
4688 		{
4689 			return UnitTypeLhs(std::copysign(x(), y()));	// no need for conversion to get the correct sign.
4690 		}
4691 
4692 		/// Overload to copy the sign from a raw double
4693 		template<class UnitTypeLhs, class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value>>
4694 		UnitTypeLhs copysign(const UnitTypeLhs x, const UNIT_LIB_DEFAULT_TYPE y) noexcept
4695 		{
4696 			return UnitTypeLhs(std::copysign(x(), y));
4697 		}
4698 
4699 		//----------------------------------
4700 		//	MIN / MAX / DIFFERENCE
4701 		//----------------------------------
4702 
4703 		/**
4704 		 * @ingroup		UnitMath
4705 		 * @brief		Positive difference
4706 		 * @details		The function returns x-y if x>y, and zero otherwise, in the same units as x.
4707 		 *				Values x and y do not have to be the same type of units, but they do have to
4708 		 *				be compatible.
4709 		 * @param[in]	x	Values whose difference is calculated.
4710 		 * @param[in]	y	Values whose difference is calculated.
4711 		 * @returns		The positive difference between x and y.
4712 		 */
4713 		template<class UnitTypeLhs, class UnitTypeRhs, class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value && traits::is_unit_t<UnitTypeRhs>::value>>
4714 		UnitTypeLhs fdim(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
4715 		{
4716 			static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Parameters of fdim() function are not compatible units.");
4717 			return UnitTypeLhs(std::fdim(x(), y.template convert<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()()));
4718 		}
4719 
4720 		/**
4721 		 * @ingroup		UnitMath
4722 		 * @brief		Maximum value
4723 		 * @details		Returns the larger of its arguments: either x or y, in the same units as x.
4724 		 *				Values x and y do not have to be the same type of units, but they do have to
4725 		 *				be compatible.
4726 		 * @param[in]	x	Values among which the function selects a maximum.
4727 		 * @param[in]	y	Values among which the function selects a maximum.
4728 		 * @returns		The maximum numeric value of its arguments.
4729 		 */
4730 		template<class UnitTypeLhs, class UnitTypeRhs, class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value && traits::is_unit_t<UnitTypeRhs>::value>>
4731 		UnitTypeLhs fmax(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
4732 		{
4733 			static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Parameters of fmax() function are not compatible units.");
4734 			return UnitTypeLhs(std::fmax(x(), y.template convert<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()()));
4735 		}
4736 
4737 		/**
4738 		 * @ingroup		UnitMath
4739 		 * @brief		Minimum value
4740 		 * @details		Returns the smaller of its arguments: either x or y, in the same units as x.
4741 		 *				If one of the arguments in a NaN, the other is returned.
4742 		 *				Values x and y do not have to be the same type of units, but they do have to
4743 		 *				be compatible.
4744 		 * @param[in]	x	Values among which the function selects a minimum.
4745 		 * @param[in]	y	Values among which the function selects a minimum.
4746 		 * @returns		The minimum numeric value of its arguments.
4747 		 */
4748 		template<class UnitTypeLhs, class UnitTypeRhs, class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value && traits::is_unit_t<UnitTypeRhs>::value>>
4749 		UnitTypeLhs fmin(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
4750 		{
4751 			static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Parameters of fmin() function are not compatible units.");
4752 			return UnitTypeLhs(std::fmin(x(), y.template convert<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()()));
4753 		}
4754 
4755 		//----------------------------------
4756 		//	OTHER FUNCTIONS
4757 		//----------------------------------
4758 
4759 		/**
4760 		 * @ingroup		UnitMath
4761 		 * @brief		Compute absolute value
4762 		 * @details		Returns the absolute value of x, i.e. |x|.
4763 		 * @param[in]	x	Value whose absolute value is returned.
4764 		 * @returns		The absolute value of x.
4765 		 */
4766 		template<class UnitType, class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
4767 		UnitType fabs(const UnitType x) noexcept
4768 		{
4769 			return UnitType(std::fabs(x()));
4770 		}
4771 
4772 		/**
4773 		 * @ingroup		UnitMath
4774 		 * @brief		Compute absolute value
4775 		 * @details		Returns the absolute value of x, i.e. |x|.
4776 		 * @param[in]	x	Value whose absolute value is returned.
4777 		 * @returns		The absolute value of x.
4778 		 */
4779 		template<class UnitType, class = std::enable_if_t<traits::is_unit_t<UnitType>::value>>
4780 		UnitType abs(const UnitType x) noexcept
4781 		{
4782 			return UnitType(std::fabs(x()));
4783 		}
4784 
4785 		/**
4786 		 * @ingroup		UnitMath
4787 		 * @brief		Multiply-add
4788 		 * @details		Returns x*y+z. The function computes the result without losing precision in
4789 		 *				any intermediate result. The resulting unit type is a compound unit of x* y.
4790 		 * @param[in]	x	Values to be multiplied.
4791 		 * @param[in]	y	Values to be multiplied.
4792 		 * @param[in]	z	Value to be added.
4793 		 * @returns		The result of x*y+z
4794 		 */
4795 		template<class UnitTypeLhs, class UnitMultiply, class UnitAdd, class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value && traits::is_unit_t<UnitMultiply>::value && traits::is_unit_t<UnitAdd>::value>>
fma(const UnitTypeLhs x,const UnitMultiply y,const UnitAdd z)4796 		auto fma(const UnitTypeLhs x, const UnitMultiply y, const UnitAdd z) noexcept -> decltype(x * y)
4797 		{
4798 			using resultType = decltype(x * y);
4799 			static_assert(traits::is_convertible_unit_t<compound_unit<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type, typename units::traits::unit_t_traits<UnitMultiply>::unit_type>, typename units::traits::unit_t_traits<UnitAdd>::unit_type>::value, "Unit types are not compatible.");
4800 			return resultType(std::fma(x(), y(), resultType(z)()));
4801 		}
4802 
4803 	}	// end namespace math
4804 }	// end namespace units
4805 
4806 //------------------------------
4807 //	std::numeric_limits
4808 //------------------------------
4809 
4810 namespace std
4811 {
4812 	template<class Units, typename T, template<typename> class NonLinearScale>
4813 	class numeric_limits<units::unit_t<Units, T, NonLinearScale>>
4814 	{
4815 	public:
min()4816 		static constexpr units::unit_t<Units, T, NonLinearScale> min()
4817 		{
4818 			return units::unit_t<Units, T, NonLinearScale>(std::numeric_limits<T>::min());
4819 		}
max()4820 		static constexpr units::unit_t<Units, T, NonLinearScale> max()
4821 		{
4822 			return units::unit_t<Units, T, NonLinearScale>(std::numeric_limits<T>::max());
4823 		}
lowest()4824 		static constexpr units::unit_t<Units, T, NonLinearScale> lowest()
4825 		{
4826 			return units::unit_t<Units, T, NonLinearScale>(std::numeric_limits<T>::lowest());
4827 		}
4828 	};
4829 }
4830 
4831 #ifdef _MSC_VER
4832 #	if _MSC_VER <= 1800
4833 #		pragma warning(pop)
4834 #		undef constexpr
4835 #		pragma pop_macro("constexpr")
4836 #		undef noexcept
4837 #		pragma pop_macro("noexcept")
4838 #		undef _ALLOW_KEYWORD_MACROS
4839 #	endif // _MSC_VER < 1800
4840 #	pragma pop_macro("pascal")
4841 #endif // _MSC_VER
4842 
4843 #endif // units_h__
4844 
4845 // For Emacs
4846 // Local Variables:
4847 // Mode: C++
4848 // c-basic-offset: 2
4849 // fill-column: 116
4850 // tab-width: 4
4851 // End:
4852