// 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. #include template consteval bool print(); template constexpr bool is_of_type(Expr) { return std::is_same_v; } namespace { using namespace units; using namespace units::si::unit_symbols; // clang-format off inline constexpr struct activity_dim : decltype(1 / isq::time_dim) {} activity_dim; inline constexpr struct activity : system_reference {} activity; // clang-format on // Named quantity/dimension and unit static_assert( is_same_v{}, int>>); // Named quantity/dimension and derived (unnamed) unit static_assert( is_same_v>>{}, int>>); // Derived (unnamed) quantity/dimension and derived (unnamed) unit static_assert(is_same_v>, derived_unit>>{}, int>>); // Base quantity as a result of dimensional transformation static_assert(is_same_v{}, int>>); // Dimensionless static_assert(is_same_v{}, int>>); // Comparisons // Named and derived dimensions (same units) static_assert(10 * si::length[m] / (2 * si::time[s]) == 5 * si::speed[m / s]); static_assert(5 * si::speed[m / s] == 10 * si::length[m] / (2 * si::time[s])); // Named and derived dimensions (different units) static_assert(10 / (2 * si::time[s]) == 5 * si::frequency[Hz]); static_assert(5 * si::frequency[Hz] == 10 / (2 * si::time[s])); // Different named dimensions template concept invalid_comparison = requires { requires !requires { 2 * R1 == 2 * R2; }; requires !requires { 2 * R2 == 2 * R1; }; }; static_assert(invalid_comparison); // static_assert(print()); // Arithmetics // Named and derived dimensions (same units) static_assert(10 * si::length[m] / (2 * si::time[s]) + 5 * si::speed[m / s] == 10 * si::speed[m / s]); static_assert(5 * si::speed[m / s] + 10 * si::length[m] / (2 * si::time[s]) == 10 * si::speed[m / s]); static_assert(10 * si::length[m] / (2 * si::time[s]) - 5 * si::speed[m / s] == 0 * si::speed[m / s]); static_assert(5 * si::speed[m / s] - 10 * si::length[m] / (2 * si::time[s]) == 0 * si::speed[m / s]); static_assert( is_same_v>>{}, int>>); static_assert( is_same_v>>{}, int>>); static_assert( is_same_v>>{}, int>>); static_assert( is_same_v>>{}, int>>); // Named and derived dimensions (different units) static_assert(10 / (2 * si::time[s]) + 5 * si::frequency[Hz] == 10 * si::frequency[Hz]); static_assert(5 * si::frequency[Hz] + 10 / (2 * si::time[s]) == 10 * si::frequency[Hz]); static_assert(10 / (2 * si::time[s]) - 5 * si::frequency[Hz] == 0 * si::frequency[Hz]); static_assert(5 * si::frequency[Hz] - 10 / (2 * si::time[s]) == 0 * si::frequency[Hz]); static_assert(is_same_v{}, int>>); static_assert(is_same_v{}, int>>); static_assert(is_same_v{}, int>>); static_assert(is_same_v{}, int>>); // Different named dimensions template consteval bool invalid_arithmetic(Ts... ts) { return requires { requires !requires { (... + ts); }; requires !requires { (... - ts); }; }; } static_assert(invalid_arithmetic(5 * activity[Bq], 5 * si::frequency[Hz])); static_assert(invalid_arithmetic(5 * activity[Bq], 10 / (2 * si::time[s]), 5 * si::frequency[Hz])); // static_assert(quantity_of); // static_assert(quantity_of); // static_assert(quantity_of); // static_assert(!quantity_of); // quantity>>, int> s = 5 * speed[m / s]; // quantity>, derived_unit>>, int> q = // 10 * length[m] / (2 * si::time[s]); // auto q1 = 10 * length[m] / (2 * si::time[s]) + 5 * speed[m / s]; // should this be allowed? // bool b1 = (10 * length[m] / (2 * si::time[s]) == 5 * speed[m / s]); // should this be allowed? // auto q2 = 10 / (2 * si::time[s]) + 5 * frequency[Hz]; // should this be allowed? // bool b2 = (10 / (2 * si::time[s]) == 5 * frequency[Hz]); // should this be allowed? // auto q3 = 5 * activity[Bq] + 5 * frequency[Hz]; // should this be allowed? // auto b3 = (5 * activity[Bq] == 5 * frequency[Hz]); // should this be allowed? // auto q4 = 5 * activity[Bq] + 10 / (2 * si::time[s]) + 5 * frequency[Hz]; // should this be allowed? // auto q5 = 120 * length[km] / (2 * si::time[h]); // not speed // auto q6 = quantity_cast(120 * length[km] / (2 * si::time[h])); // auto q7 = quantity_cast(120 * length[km] / (2 * si::time[h])); // quantity s = q5; // should this implicit conversion be allowed? } // namespace namespace units::si { // derived unit expression template syntax verification static_assert(is_of_type>>(1 / second)); static_assert(is_of_type(1 / (1 / second))); static_assert(is_of_type(one * second)); static_assert(is_of_type(second * one)); static_assert(is_of_type>>(one * (1 / second))); static_assert(is_of_type>>(1 / second * one)); static_assert(is_of_type>(metre * second)); static_assert(is_of_type>>(metre * metre)); static_assert(is_of_type, struct second>>(metre * metre * second)); static_assert(is_of_type, struct second>>(metre * second * metre)); static_assert(is_of_type, struct second>>(metre * (second * metre))); static_assert(is_of_type, struct second>>(second * (metre * metre))); static_assert(is_of_type>>(1 / second * metre)); static_assert(is_of_type(1 / second * second)); static_assert(is_of_type(second / one)); static_assert(is_of_type>>(1 / second / one)); static_assert(is_of_type(metre / second * second)); static_assert(is_of_type>>>(1 / second * (1 / second))); static_assert(is_of_type>>>(1 / (second * second))); static_assert(is_of_type>>(1 / (1 / (second * second)))); static_assert(is_of_type>>>(metre / second * (1 / second))); static_assert(is_of_type, per>>>( metre / second * (metre / second))); static_assert(is_of_type(metre / second * (second / metre))); static_assert(is_of_type>>(watt / joule)); static_assert(is_of_type>>(joule / watt)); // comparisons of equivalent units static_assert(metre / metre == one); // static_assert(metre * metre == square_metre); // static_assert(second * second == second_squared); // static_assert(second * second * second == second_cubed); // static_assert(second * (second * second) == second_cubed); // static_assert(second_squared * second == second_cubed); // static_assert(second * second_squared == second_cubed); // static_assert(1 / second * metre == metre / second); // static_assert(metre * (1 / second) == metre / second); // static_assert((metre / second) * (1 / second) == metre / second / second); // static_assert((metre / second) * (1 / second) == metre / (second * second)); // static_assert((metre / second) * (1 / second) == metre / second_squared); // static_assert(hertz == 1 / second); // static_assert(newton == kilogram * metre / second_squared); // static_assert(joule == kilogram * square_metre / second_squared); // static_assert(joule == newton * metre); // static_assert(watt == joule / second); // static_assert(watt == kilogram * square_metre / second_cubed); // static_assert(1 / frequency_dim == second); // static_assert(frequency_dim * second == one); // static_assert(metre * metre == area_dim); // static_assert(metre * metre != volume_dim); // static_assert(area_dim / metre == metre); // static_assert(metre * metre * metre == volume_dim); // static_assert(area_dim * metre == volume_dim); // static_assert(volume_dim / metre == area_dim); // static_assert(volume_dim / metre / metre == metre); // static_assert(area_dim * area_dim / metre == volume_dim); // static_assert(area_dim * (area_dim / metre) == volume_dim); // static_assert(volume_dim / (metre * metre) == metre); // static_assert(metre / second == speed_dim); // static_assert(metre * second != speed_dim); // static_assert(metre / second / second != speed_dim); // static_assert(metre / speed_dim == second); // static_assert(speed_dim * second == metre); // static_assert(metre / second / second == acceleration_dim); // static_assert(metre / (second * second) == acceleration_dim); // static_assert(speed_dim / second == acceleration_dim); // static_assert(speed_dim / acceleration_dim == second); // static_assert(acceleration_dim * second == speed_dim); // static_assert(acceleration_dim * (second * second) == metre); // static_assert(acceleration_dim / speed_dim == frequency_dim); // Bq + Hz should not compile // Bq + Hz + 1/s should compile? } // namespace units::si namespace units { template inline constexpr bool is_exactly_quantity_of = is_same_v && is_same_v; } namespace units::isq::si { // quantity tests // static_assert( // is_exactly_quantity_of>>); // static_assert(QuantityOf>); // static_assert(QuantityOf>); // // TODO Should this compile? } // namespace units::isq::si // using namespace units; // using namespace units::si; // using namespace units::si::unit_symbols; // /* Frequency */ auto freq1 = 20 * frequency[Hz]; // // /* Frequency */ auto freq2 = 20 / (1 * si::time[s]); // quantity freq3(20); // quantity freq4(20); // quantity freq5(20); // /* Speed */ auto speed1 = 20 * speed[m / s]; // /* Speed */ auto speed2 = 20 * (length[m] / si::time[s]); // quantity speed3(20); // quantity speed4(20); // constexpr auto avg_speed(quantity d, quantity t) { return d / t; } int main() { // print(); // print(); // // print(); // print(); // print(); // print(); // print(); // print(); // print(); // print(); } // 1 * joule + 1 * erg ??? // joule * erg??? // joule / erg??? // auto d1 = 42 * isq::length_dim[si::kilo]; // auto d2 = 42 * isq::length_dim[cgs::centimetre]; // auto s1 = 42 * isq::speed_dim[si::metre / si::second]; // auto s2 = 42 * isq::speed_dim[cgs::centimetre / si::second]; // auto e1 = 42 * isq::energy_dim[si::joule]; // auto e2 = 42 * isq::energy_dim[cgs::erg]; // auto e2_bad = 42 * isq::energy_dim[cgs::erg / si::second]; // auto p1 = 42 * isq::power_dim[si::watt]; // auto p2 = 42 * isq::power_dim[cgs::erg / si::second]; // type of Rep{1} * (mag * mag_power<10, -34> * energy[joule] * time[second]) // and inline constexpr auto planck_constant = Rep{1} * mag_planck * energy[joule] * time[second];