// The MIT License (MIT) // // Copyright (c) 2018 Mateusz Pusz // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #pragma once #include #include namespace units { template U, Representation Rep> class quantity; template U> struct reference; namespace detail { template using reference_multiply_impl = reference::ratio) * (U2::ratio / dimension_unit::ratio) * dimension_unit::ratio>>; template using reference_divide_impl = reference::ratio) / (U2::ratio / dimension_unit::ratio) * dimension_unit::ratio>>; } // namespace detail template using reference_multiply = detail::reference_multiply_impl< dimension_multiply, typename R1::dimension, typename R1::unit, typename R2::dimension, typename R2::unit>; template using reference_divide = detail::reference_divide_impl< dimension_divide, typename R1::dimension, typename R1::unit, typename R2::dimension, typename R2::unit>; /** * @brief The type for quantity references * * This type is intended to be used in the quantity references definition: * * @code{.cpp} * namespace length_references { * * inline constexpr auto m = reference{}; * inline constexpr auto km = reference{}; * * } * * namespace references { * * using namespace length_references; * * } * @endcode * * Quantity references simplify quantity creation: * * @code{.cpp} * using namespace units::isq::si::references; * * auto d = 123 * m; * auto v = 70 * (km / h); * @endcode * * Also, it is allowed to define custom quantity references from existing ones: * * @code{.cpp} * constexpr auto Nm = N * m; * constexpr auto mph = mi / h; * @endcode * * The following syntaxes are not allowed: * `2 / s`, `km * 3`, `s / 4`, `70 * km / h`. */ template U> struct reference { using dimension = D; using unit = U; // Hidden Friends // Below friend functions are to be found via argument-dependent lookup only template [[nodiscard]] friend constexpr reference_multiply operator*(reference, R2) { return {}; } template [[nodiscard]] friend constexpr reference_divide operator/(reference, R2) { return {}; } template [[nodiscard]] friend constexpr Quantity auto operator*(const Rep& lhs, reference) { return quantity(lhs); } friend void /*Use `q * (1 * r)` rather than `q * r`.*/ operator*(Quantity auto, reference) = delete; template [[nodiscard]] friend constexpr bool operator==(reference, R2) { return false; } [[nodiscard]] friend constexpr bool operator==(reference, reference) { return true; } }; // type traits namespace detail { template inline constexpr bool is_reference> = true; } // namespace detail } // namespace units