| 
									
										
										
										
											2023-06-21 10:55:18 +02:00
										 |  |  | # Value Conversions
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Value-preserving conversions
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```cpp | 
					
						
							|  |  |  | auto q1 = 5 * km; | 
					
						
							| 
									
										
										
										
											2023-08-23 16:46:15 +02:00
										 |  |  | std::cout << q1.in(m) << '\n'; | 
					
						
							| 
									
										
										
										
											2023-06-21 10:55:18 +02:00
										 |  |  | quantity<si::metre, int> q2 = q1; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-26 11:07:21 +01:00
										 |  |  | The second line above converts the current quantity to the one expressed in meters and prints its | 
					
						
							|  |  |  | contents. The third line converts the quantity expressed in kilometers into the one measured | 
					
						
							|  |  |  | in meters. | 
					
						
							| 
									
										
										
										
											2023-06-21 10:55:18 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | In case a user would like to perform an opposite transformation: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```cpp | 
					
						
							|  |  |  | auto q1 = 5 * m; | 
					
						
							| 
									
										
										
										
											2023-08-23 16:46:15 +02:00
										 |  |  | std::cout << q1.in(km) << '\n'; | 
					
						
							| 
									
										
										
										
											2023-06-21 10:55:18 +02:00
										 |  |  | quantity<si::kilo<si::metre>, int> q2 = q1; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Both conversions will fail to compile. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | There are two ways to make the above work. The first solution is to use a floating-point | 
					
						
							|  |  |  | representation type: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```cpp | 
					
						
							|  |  |  | auto q1 = 5. * m; | 
					
						
							| 
									
										
										
										
											2023-08-23 16:46:15 +02:00
										 |  |  | std::cout << q1.in(km) << '\n'; | 
					
						
							| 
									
										
										
										
											2023-06-21 10:55:18 +02:00
										 |  |  | quantity<si::kilo<si::metre>> q2 = q1; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-13 09:00:21 +02:00
										 |  |  | or | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```cpp | 
					
						
							|  |  |  | auto q1 = 5 * m; | 
					
						
							|  |  |  | std::cout << value_cast<double>(q1).in(km) << '\n'; | 
					
						
							|  |  |  | quantity<si::kilo<si::metre>> q2 = q1;  // double by default | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 18:57:39 +02:00
										 |  |  | !!! important | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The **mp-units** library follows [`std::chrono::duration`](https://en.cppreference.com/w/cpp/chrono/duration) | 
					
						
							|  |  |  |     logic and treats floating-point types as value-preserving. | 
					
						
							| 
									
										
										
										
											2023-06-21 10:55:18 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Value-truncating conversions
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The second solution is to force a truncating conversion: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```cpp | 
					
						
							|  |  |  | auto q1 = 5 * m; | 
					
						
							|  |  |  | std::cout << value_cast<km>(q1) << '\n'; | 
					
						
							| 
									
										
										
										
											2023-09-13 10:44:50 +02:00
										 |  |  | quantity<si::kilo<si::metre>, int> q2 = q1.force_in(km); | 
					
						
							| 
									
										
										
										
											2023-06-21 10:55:18 +02:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This explicit cast makes it clear that something unsafe is going on. It is easy to spot in code | 
					
						
							|  |  |  | reviews or while chasing a bug in the source code. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-13 10:44:50 +02:00
										 |  |  | !!! note | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     `q.force_in(U)` is just a shortcut to run `value_cast<U>(q)`. There is no difference in behavior | 
					
						
							|  |  |  |     between those two interfaces. `q.force_in(U)` was added for consistency with `q.in(U)` and | 
					
						
							|  |  |  |     `q.force_numerical_value_in(U)`. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 10:55:18 +02:00
										 |  |  | Another place where this cast is useful is when a user wants to convert a quantity with | 
					
						
							| 
									
										
										
										
											2023-12-26 11:07:21 +01:00
										 |  |  | a floating-point representation to the one using an integral one. Again, this is a truncating | 
					
						
							| 
									
										
										
										
											2023-06-21 10:55:18 +02:00
										 |  |  | conversion, so an explicit cast is needed: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```cpp | 
					
						
							|  |  |  | quantity<si::metre, int> q3 = value_cast<int>(3.14 * m); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | !!! info | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-26 11:07:21 +01:00
										 |  |  |     It is often OK to use an integral as a representation type, but in general, floating-point | 
					
						
							| 
									
										
										
										
											2023-06-21 10:55:18 +02:00
										 |  |  |     types provide better precision and are privileged in the library as they are considered | 
					
						
							|  |  |  |     to be value-preserving. | 
					
						
							| 
									
										
										
										
											2023-12-19 18:19:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | In some cases, a unit and a representation type should be changed simultaneously. Moreover, | 
					
						
							|  |  |  | sometimes, the order of doing those operations matters. In such cases, the library provides | 
					
						
							|  |  |  | the `value_cast<U, Rep>(q)` which always returns the most precise result: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | === "C++23" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ```cpp | 
					
						
							|  |  |  |     inline constexpr struct dim_currency : base_dimension<"$"> {} dim_currency; | 
					
						
							|  |  |  |     inline constexpr struct currency : quantity_spec<dim_currency> {} currency; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     inline constexpr struct us_dollar : named_unit<"USD", kind_of<currency>> {} us_dollar; | 
					
						
							|  |  |  |     inline constexpr struct scaled_us_dollar : named_unit<"USD_s", mag_power<10, -8> * us_dollar> {} scaled_us_dollar; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     namespace unit_symbols { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     inline constexpr auto USD = us_dollar; | 
					
						
							|  |  |  |     inline constexpr auto USD_s = scaled_us_dollar; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     }  // namespace unit_symbols | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     using Price = quantity<currency[us_dollar], double>; | 
					
						
							|  |  |  |     using Scaled = quantity<currency[scaled_us_dollar], std::int64_t>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Price price = 12.95 * USD; | 
					
						
							|  |  |  |     Scaled spx = value_cast<USD_s, std::int64_t>(price); | 
					
						
							|  |  |  |     ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | === "C++20" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ```cpp | 
					
						
							|  |  |  |     inline constexpr struct dim_currency : base_dimension<"$"> {} dim_currency; | 
					
						
							|  |  |  |     inline constexpr struct currency : quantity_spec<currency, dim_currency> {} currency; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     inline constexpr struct us_dollar : named_unit<"USD", kind_of<currency>> {} us_dollar; | 
					
						
							|  |  |  |     inline constexpr struct scaled_us_dollar : named_unit<"USD_s", mag_power<10, -8> * us_dollar> {} scaled_us_dollar; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     namespace unit_symbols { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     inline constexpr auto USD = us_dollar; | 
					
						
							|  |  |  |     inline constexpr auto USD_s = scaled_us_dollar; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     }  // namespace unit_symbols | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     using Price = quantity<currency[us_dollar], double>; | 
					
						
							|  |  |  |     using Scaled = quantity<currency[scaled_us_dollar], std::int64_t>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Price price = 12.95 * USD; | 
					
						
							|  |  |  |     Scaled spx = value_cast<USD_s, std::int64_t>(price); | 
					
						
							|  |  |  |     ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | === "Portable" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ```cpp | 
					
						
							|  |  |  |     inline constexpr struct dim_currency : base_dimension<"$"> {} dim_currency; | 
					
						
							|  |  |  |     QUANTITY_SPEC(currency, dim_currency); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     inline constexpr struct us_dollar : named_unit<"USD", kind_of<currency>> {} us_dollar; | 
					
						
							|  |  |  |     inline constexpr struct scaled_us_dollar : named_unit<"USD_s", mag_power<10, -8> * us_dollar> {} scaled_us_dollar; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     namespace unit_symbols { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     inline constexpr auto USD = us_dollar; | 
					
						
							|  |  |  |     inline constexpr auto USD_s = scaled_us_dollar; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     }  // namespace unit_symbols | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     using Price = quantity<currency[us_dollar], double>; | 
					
						
							|  |  |  |     using Scaled = quantity<currency[scaled_us_dollar], std::int64_t>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Price price = 12.95 * USD; | 
					
						
							|  |  |  |     Scaled spx = value_cast<USD_s, std::int64_t>(price); | 
					
						
							|  |  |  |     ``` |