Skip to content

Instantly share code, notes, and snippets.

@notfoundry
Last active June 16, 2018 17:17
Show Gist options
  • Select an option

  • Save notfoundry/387d70ba35f60cdc96d2a82e27b8373f to your computer and use it in GitHub Desktop.

Select an option

Save notfoundry/387d70ba35f60cdc96d2a82e27b8373f to your computer and use it in GitHub Desktop.
Strongly-dimensioned quantity types for C++11
#include <cstddef>
#include <type_traits>
#include <boost/mp11/list.hpp>
#include <boost/mp11/bind.hpp>
#include <boost/mp11/utility.hpp>
#include <boost/mp11/function.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/map.hpp>
namespace sdim {
template <typename ExpUnitList, typename Value = double>
struct val;
template <typename FromUnit, typename ToUnit>
struct unit_conversion;
#ifdef STRONGDIM_ENFORCE_CORRECTNESS
namespace detail {
struct test_unit_1 {};
struct test_unit_2 {};
struct test_unit_3 {};
struct test_unit_4 {};
struct test_unit_5 {};
}
template <>
struct unit_conversion<detail::test_unit_1, detail::test_unit_2> {
constexpr static auto conversion_factor = 2;
};
template <>
struct unit_conversion<detail::test_unit_3, detail::test_unit_4> {
constexpr static auto conversion_factor = 3;
};
#endif //STRONGDIM_ENFORCE_CORRECTNESS
namespace detail {
using namespace boost::mp11;
template <bool Cond, template <typename...> class DeferredCond, typename... Args>
struct lazy_enable_if {
using type = void;
};
template <template <typename...> class DeferredCond, typename... Args>
struct lazy_enable_if<false, DeferredCond, Args...> {
using type = typename std::enable_if<DeferredCond<Args...>::value>::type;
};
template <typename Unit, int Exponent>
struct exp_unit {
using unit_type = Unit;
constexpr static int exponent = Exponent;
};
template <typename T>
struct is_exp_unit : std::false_type {};
template <typename Unit, int Exponent>
struct is_exp_unit<exp_unit<Unit, Exponent>> : std::true_type {};
template <typename UnitList>
struct wrap_units_as_exp_units_if_present {
private:
template <typename Unit>
using wrap_unit_if_necessary = mp_if<
mp_or<is_exp_unit<Unit>, mp_is_list<Unit>>,
Unit,
exp_unit<Unit, 1>
>;
template <typename Accumulator, typename Unit>
using update_accumulator = mp_push_back<Accumulator, wrap_unit_if_necessary<Unit>>;
public:
using type = mp_fold<UnitList, mp_list<>, update_accumulator>;
};
#ifdef STRONGDIM_ENFORCE_CORRECTNESS
static_assert(
std::is_same<
typename wrap_units_as_exp_units_if_present<mp_list<>>::type,
mp_list<>
>::value,
"metafunction wrap_units_as_exp_units_if_present failed contract test");
static_assert(
std::is_same<
typename wrap_units_as_exp_units_if_present<mp_list<
test_unit_1, test_unit_2, exp_unit<test_unit_3, 2>
>>::type,
mp_list<exp_unit<test_unit_1, 1>, exp_unit<test_unit_2, 1>, exp_unit<test_unit_3, 2>>
>::value,
"metafunction wrap_units_as_exp_units_if_present failed contract test");
#endif //STRONGDIM_ENFORCE_CORRECTNESS
template <typename UnitList>
struct consolidate_exp_unit_exponents_if_units_duplicated {
private:
template <typename MapUnit, typename MapExponent, typename CurrentExponent>
using sum_exponents = mp_plus<MapExponent, CurrentExponent>;
template <typename Map, typename Unit, typename Exponent>
using update_map_impl = mp_map_update_q<Map, mp_list<Unit, Exponent>, mp_bind_back<sum_exponents, Exponent>>;
template <typename Map, typename ExpUnit>
using update_map = update_map_impl<Map, typename ExpUnit::unit_type, mp_int<ExpUnit::exponent>>;
using unit_to_accumulated_exponent_map = mp_fold<UnitList, mp_list<>, update_map>;
template <typename UnitAndExponentPair>
using is_exponent_zero = mp_bool<mp_second<UnitAndExponentPair>::value == 0>;
using unit_to_accumulated_exponent_map_after_removing_cancelled_units = mp_remove_if<unit_to_accumulated_exponent_map, is_exponent_zero>;
template <typename UnitAndExponentPair>
using unpack_unit_and_exponent = exp_unit<mp_first<UnitAndExponentPair>, mp_second<UnitAndExponentPair>::value>;
public:
using type = mp_transform<unpack_unit_and_exponent, unit_to_accumulated_exponent_map_after_removing_cancelled_units>;
};
#ifdef STRONGDIM_ENFORCE_CORRECTNESS
static_assert(
std::is_same<
typename consolidate_exp_unit_exponents_if_units_duplicated<mp_list<
>>::type,
mp_list<>
>::value,
"metafunction consolidate_exp_unit_exponents_if_units_duplicated failed contract test");
static_assert(
std::is_same<
typename consolidate_exp_unit_exponents_if_units_duplicated<mp_list<
exp_unit<test_unit_2, 2>, exp_unit<test_unit_1, 2>, exp_unit<test_unit_1, 1>, exp_unit<test_unit_3, 4>
>>::type,
mp_list<exp_unit<test_unit_2, 2>, exp_unit<test_unit_1, 3>, exp_unit<test_unit_3, 4>>
>::value,
"metafunction consolidate_exp_unit_exponents_if_units_duplicated failed contract test");
#endif //STRONGDIM_ENFORCE_CORRECTNESS
template <typename TypeOrTypeListList, typename Accumulator = mp_list<>, bool Done = mp_empty<TypeOrTypeListList>::value>
struct flatten;
template <typename TypeOrTypeList, typename Accumulator>
struct update_flattening_accumulator;
template <
template <typename...> class ListForTypes, typename... Types,
template <typename...> class ListForAccumulator, typename... AccumulatedTypes
>
struct update_flattening_accumulator<ListForTypes<Types...>, ListForAccumulator<AccumulatedTypes...>> {
using inner_type_list = ListForTypes<Types...>;
using inner_flattening_result = typename flatten<inner_type_list>::type;
using type = mp_append<ListForAccumulator<AccumulatedTypes...>, inner_flattening_result>;
};
template <typename Type, template <typename...> class ListForAccumulator, typename... AccumulatedTypes>
struct update_flattening_accumulator<Type, ListForAccumulator<AccumulatedTypes...>> {
using type = ListForAccumulator<AccumulatedTypes..., Type>;
};
template <typename TypeOrTypeListList, typename Accumulator, bool Done>
struct flatten {
using current_type = mp_front<TypeOrTypeListList>;
using updated_accumulator = typename update_flattening_accumulator<current_type, Accumulator>::type;
using next_type_or_type_list_list_step = mp_pop_front<TypeOrTypeListList>;
using type = typename flatten<next_type_or_type_list_list_step, updated_accumulator>::type;
};
template <typename TypeOrTypeListList, typename Accumulator>
struct flatten<TypeOrTypeListList, Accumulator, true> {
using type = Accumulator;
};
#ifdef STRONGDIM_ENFORCE_CORRECTNESS
static_assert(
std::is_same<
typename flatten<mp_list<>>::type,
mp_list<>
>::value,
"metafunction flatten failed contract test");
static_assert(
std::is_same<
typename flatten<mp_list<
void*,
mp_list<int, long, mp_list<char, short>>,
int*
>>::type,
mp_list<void*, int, long, char, short, int*>
>::value,
"metafunction flatten failed contract test");
#endif //STRONGDIM_ENFORCE_CORRECTNESS
template <typename UnitList>
struct normalize_unit_list {
private:
using flattended_unit_list = typename flatten<UnitList>::type;
using wrapped_exp_unit_list = typename wrap_units_as_exp_units_if_present<flattended_unit_list>::type;
using consolidated_exp_unit_list = typename consolidate_exp_unit_exponents_if_units_duplicated<wrapped_exp_unit_list>::type;
public:
using type = consolidated_exp_unit_list;
};
template <
typename ThisUnitList, typename ThatUnitList,
bool SameSize = (mp_size<ThisUnitList>::value == mp_size<ThatUnitList>::value)
> struct are_list_contents_equal {
private:
template <typename Accumulator, typename Unit>
using this_list_contains = mp_push_back<Accumulator, mp_contains<ThisUnitList, Unit>>;
using unit_contains_check_results = mp_fold<ThatUnitList, mp_list<>, this_list_contains>;
public:
constexpr static bool value = mp_not<mp_contains<unit_contains_check_results, mp_false>>::value;
};
template <typename ThisUnitList, typename ThatUnitList>
struct are_list_contents_equal<ThisUnitList, ThatUnitList, false> {
constexpr static bool value = false;
};
template <typename FirstUnit, typename SecondUnit>
struct are_units_equivalent {
private:
using normalized_first_exp_units = typename normalize_unit_list<mp_list<FirstUnit>>::type;
using normalized_second_exp_units = typename normalize_unit_list<mp_list<SecondUnit>>::type;
public:
constexpr static bool value = are_list_contents_equal<normalized_first_exp_units, normalized_second_exp_units>::value;
};
template <typename T>
struct is_val : std::false_type {};
template <typename ExpUnitList, typename Value>
struct is_val<val<ExpUnitList, Value>> : std::true_type {};
template <typename OtherVal, typename ExpUnitListToCompare, bool IsVal = is_val<OtherVal>::value>
struct is_equivalent_val {
constexpr static bool value = are_units_equivalent<ExpUnitListToCompare, typename OtherVal::unit_list_type>::value;
};
template <typename OtherVal, typename ExpUnitListToCompare>
struct is_equivalent_val<OtherVal, ExpUnitListToCompare, false> : std::false_type {};
template <typename... Units>
struct take_unit_list_product {
private:
using unit_list = mp_list<Units...>;
using flattened_and_normalized_exp_unit_list = typename normalize_unit_list<unit_list>::type;
public:
using type = flattened_and_normalized_exp_unit_list;
};
template <typename ExpUnitList, template <typename, int> class F>
struct apply_to_exp_units {
private:
template <typename ExpUnit>
using apply_function = F<typename ExpUnit::unit_type, ExpUnit::exponent>;
public:
using type = mp_transform<apply_function, ExpUnitList>;
};
template <typename OfUnit, typename ToUnit>
struct take_unit_ratio {
private:
using normalized_numerator_exp_units = typename normalize_unit_list<mp_list<OfUnit>>::type;
using normalized_denominator_exp_units = typename normalize_unit_list<mp_list<ToUnit>>::type;
template <typename Unit, int Exponent>
using invert_exponent_sign = exp_unit<Unit, -Exponent>;
using exp_inverted_denominator_units = typename apply_to_exp_units<normalized_denominator_exp_units, invert_exponent_sign>::type;
using concatenated_exp_unit_list = mp_append<normalized_numerator_exp_units, exp_inverted_denominator_units>;
using consolidated_exp_unit_list = typename consolidate_exp_unit_exponents_if_units_duplicated<concatenated_exp_unit_list>::type;
public:
using type = consolidated_exp_unit_list;
};
template <typename Unit, int Exponent>
struct take_unit_power {
private:
using normalized_exp_units = typename normalize_unit_list<mp_list<Unit>>::type;
template <typename InnerUnit, int InnerUnitExponent>
using multiply_unit_exponent_with_chosen_exponent = exp_unit<InnerUnit, InnerUnitExponent * Exponent>;
public:
using type = typename apply_to_exp_units<normalized_exp_units, multiply_unit_exponent_with_chosen_exponent>::type;
};
template <typename UnitConversion>
struct inverse_conversion {
using unit_conversion = UnitConversion;
};
template <typename UnitConversion>
struct unit_conversion_to_conversion_function {
template <typename Value>
constexpr static Value convert(Value value) {
return value * UnitConversion::conversion_factor;
}
};
template <typename UnitConversion>
struct unit_conversion_to_conversion_function<inverse_conversion<UnitConversion>> {
template <typename Value>
constexpr static Value convert(Value value) {
return value / UnitConversion::conversion_factor;
}
};
template <typename GivenUnitSet, typename RequiredUnitSet, bool SameSize = (mp_size<GivenUnitSet>::value == mp_size<RequiredUnitSet>::value)>
struct is_valid_unit_conversion_possible {
template <typename MapExponent, typename MapUnitCount>
using increment_unit_count_for_exponent = mp_int<MapUnitCount::value + 1>;
template <typename ExponentToUnitCountMap, typename ExpUnit>
using count_units_with_same_exponent = mp_map_update<
ExponentToUnitCountMap,
mp_list<mp_int<ExpUnit::exponent>, mp_int<1>>,
increment_unit_count_for_exponent
>;
using exponent_to_unit_count_map = mp_fold<mp_append<GivenUnitSet, RequiredUnitSet>, mp_list<>, count_units_with_same_exponent>;
constexpr static int units_to_find_if_conversion_possible = 2;
using unit_counts = mp_transform<mp_second, exponent_to_unit_count_map>;
template <typename I>
using is_power_of_two = mp_bool<I::value % 2 == 0>;
using unpaired_units_count = mp_size<mp_remove_if<unit_counts, is_power_of_two>>;
constexpr static bool value = (unpaired_units_count::value == 0);
};
template <typename GivenUnitSet, typename RequiredUnitSet>
struct is_valid_unit_conversion_possible<GivenUnitSet, RequiredUnitSet, false> {
constexpr static bool value = false;
};
#ifdef STRONGDIM_ENFORCE_CORRECTNESS
static_assert(
is_valid_unit_conversion_possible<
mp_list<>,
mp_list<>
>::value,
"metafunction is_valid_unit_conversion_possible failed contract test");
static_assert(
is_valid_unit_conversion_possible<
mp_list<exp_unit<test_unit_1, 2>, exp_unit<test_unit_3, 1>, exp_unit<test_unit_2, 2>>,
mp_list<exp_unit<test_unit_1, 1>, exp_unit<test_unit_2, 2>, exp_unit<test_unit_3, 2>>
>::value,
"metafunction is_valid_unit_conversion_possible failed contract test");
static_assert(
!is_valid_unit_conversion_possible<
mp_list<exp_unit<test_unit_1, 4>, exp_unit<test_unit_3, 1>, exp_unit<test_unit_2, 2>>,
mp_list<exp_unit<test_unit_1, 1>, exp_unit<test_unit_2, 2>, exp_unit<test_unit_3, 2>>
>::value,
"metafunction is_valid_unit_conversion_possible failed contract test");
#endif //STRONGDIM_ENFORCE_CORRECTNESS
template <typename FirstConversionFunction, typename SecondConversionFunction>
struct apply_both_conversion_functions {
template <typename Value>
constexpr static Value convert(Value value) {
return SecondConversionFunction::convert(FirstConversionFunction::convert(value));
}
};
struct identity_conversion_function {
template <typename Value>
constexpr static Value convert(Value value) {
return value;
}
};
template <typename ConversionFunctionList>
struct sequental_conversion_function_applier {
private:
template <typename Accumulator, typename ConversionFunction>
using make_seq_application = apply_both_conversion_functions<Accumulator, ConversionFunction>;
using sequential_converter = mp_fold<mp_pop_front<ConversionFunctionList>, mp_front<ConversionFunctionList>, make_seq_application>;
public:
template <typename Value>
constexpr static Value convert(Value value) {
return sequential_converter::convert(value);
}
};
template <typename InList, typename FromList>
struct remove_all {
private:
template <typename Accumulator, typename T>
using do_removal = mp_remove<Accumulator, T>;
public:
using type = mp_fold<InList, FromList, do_removal>;
};
template <
typename GivenUnitSet, typename RequiredUnitSet,
bool ConversionPossible = is_valid_unit_conversion_possible<GivenUnitSet, RequiredUnitSet>::value
>
struct try_make_conversion_function {
private:
static_assert(
mp_size<GivenUnitSet>::value == mp_size<RequiredUnitSet>::value,
"given and required unit sets must be the same size");
using unfulfilled_required_exp_unit_set = typename remove_all<GivenUnitSet, RequiredUnitSet>::type;
using unused_given_exp_unit_set = typename remove_all<RequiredUnitSet, GivenUnitSet>::type;
template <typename ExpUnit>
using to_unit = typename ExpUnit::unit_type;
using unfulfilled_required_unit_set = mp_transform<to_unit, unfulfilled_required_exp_unit_set>;
using unused_given_unit_set = mp_transform<to_unit, unused_given_exp_unit_set>;
template <
typename RemainingUnusedGivenUnitSet, typename FoundUnitConverterSet,
typename GivenUnit, typename UnitConverter
>
using update_inner_reduction_accumulators_impl = mp_list<
mp_remove<RemainingUnusedGivenUnitSet, GivenUnit>,
mp_push_back<FoundUnitConverterSet, unit_conversion_to_conversion_function<UnitConverter>>
>;
template <typename Accumulators, typename GivenUnit, typename DeferredUnitConverter>
using update_inner_reduction_accumulators = update_inner_reduction_accumulators_impl<
mp_first<Accumulators>, mp_second<Accumulators>, GivenUnit, typename DeferredUnitConverter::type
>;
template <typename GivenUnit, typename RequiredUnit>
using make_unit_conversion = unit_conversion<GivenUnit, RequiredUnit>;
template <typename GivenUnit, typename RequiredUnit>
using make_inverse_unit_conversion = inverse_conversion<make_unit_conversion<RequiredUnit, GivenUnit>>;
template <typename GivenUnit, typename RequiredUnit>
using get_unit_conversion_factor_type = decltype(unit_conversion<GivenUnit, RequiredUnit>::conversion_factor);
template <typename Accumulators, typename GivenUnit, typename RequiredUnit>
using do_inner_reduction_for_inverse_conversion = mp_eval_if<
mp_not<mp_valid<get_unit_conversion_factor_type, RequiredUnit, GivenUnit>>,
Accumulators,
update_inner_reduction_accumulators,
Accumulators,
GivenUnit,
mp_defer<
make_inverse_unit_conversion,
GivenUnit,
RequiredUnit
>
>;
template <typename Accumulators, typename GivenUnit, typename RequiredUnit>
using do_inner_reduction_for_direct_conversion = mp_eval_if<
mp_not<mp_valid<get_unit_conversion_factor_type, GivenUnit, RequiredUnit>>,
do_inner_reduction_for_inverse_conversion<Accumulators, GivenUnit, RequiredUnit>,
update_inner_reduction_accumulators,
Accumulators,
GivenUnit,
mp_defer<
make_unit_conversion,
GivenUnit,
RequiredUnit
>
>;
template <typename RemainingUnusedGivenUnitSet, typename FoundUnitConverterSet, typename RequiredUnit>
using inner_reduction = mp_fold_q<
RemainingUnusedGivenUnitSet,
mp_list<RemainingUnusedGivenUnitSet, FoundUnitConverterSet>,
mp_bind_back<do_inner_reduction_for_direct_conversion, RequiredUnit>
>;
template <typename Accumulators, typename RequiredUnit>
using do_outer_reduction = inner_reduction<mp_first<Accumulators>, mp_second<Accumulators>, RequiredUnit>;
using outer_reduction = mp_fold<
unfulfilled_required_unit_set,
mp_list<unused_given_unit_set, mp_list<>>,
do_outer_reduction
>;
using unit_conversion_function_sequence = mp_second<outer_reduction>;
using conversion_failed = mp_bool<mp_size<unit_conversion_function_sequence>::value != mp_size<unfulfilled_required_unit_set>::value>;
using final_conversion_function = mp_eval_if<
conversion_failed,
void,
sequental_conversion_function_applier,
unit_conversion_function_sequence
>;
public:
using type = final_conversion_function;
constexpr static bool could_convert = !conversion_failed::value;
};
template <typename GivenUnitSet, typename RequiredUnitSet>
struct try_make_conversion_function<GivenUnitSet, RequiredUnitSet, false> {
using type = void;
constexpr static bool could_convert = false;
};
#ifdef STRONGDIM_ENFORCE_CORRECTNESS
static_assert(
try_make_conversion_function<
mp_list<exp_unit<test_unit_1, 1>, exp_unit<test_unit_3, 1>, exp_unit<test_unit_5, 1>>,
mp_list<exp_unit<test_unit_5, 1>, exp_unit<test_unit_2, 1>, exp_unit<test_unit_4, 1>>
>::could_convert,
"metafunction try_make_conversion_function failed contract test");
static_assert(
try_make_conversion_function<
mp_list<exp_unit<test_unit_1, 1>, exp_unit<test_unit_3, 1>, exp_unit<test_unit_5, 1>>,
mp_list<exp_unit<test_unit_5, 1>, exp_unit<test_unit_2, 1>, exp_unit<test_unit_4, 1>>
>::type::convert(2) == 2 * unit_conversion<test_unit_1, test_unit_2>::conversion_factor * unit_conversion<test_unit_3, test_unit_4>::conversion_factor,
"metafunction try_make_conversion_function failed contract test");
static_assert(
!try_make_conversion_function<
mp_list<exp_unit<test_unit_5, 1>, exp_unit<test_unit_1, 1>>,
mp_list<exp_unit<test_unit_2, 1>, exp_unit<test_unit_4, 1>>
>::could_convert,
"metafunction try_make_conversion_function failed contract test");
#endif //STRONGDIM_ENFORCE_CORRECTNESS
template <typename GivenUnitSet, typename RequiredUnitSet, bool UnitsEquivalent = are_list_contents_equal<GivenUnitSet, RequiredUnitSet>::value>
struct find_unit_conversion {
using type = identity_conversion_function;
constexpr static bool could_convert = true;
};
template <typename GivenUnitSet, typename RequiredUnitSet>
struct find_unit_conversion<GivenUnitSet, RequiredUnitSet, false> : try_make_conversion_function<GivenUnitSet, RequiredUnitSet> {};
}
template <typename... Units>
using product = typename detail::take_unit_list_product<Units...>::type;
template <typename OfUnit, typename ToUnit>
using rate = typename detail::take_unit_ratio<OfUnit, ToUnit>::type;
template <typename Unit, int Exponent>
using power = typename detail::take_unit_power<Unit, Exponent>::type;
template <typename ExpUnitList, typename Value>
struct val {
public:
using unit_list_type = typename detail::normalize_unit_list<boost::mp11::mp_list<ExpUnitList>>::type;
using value_type = Value;
private:
template <typename OtherNum>
using value_type_when_mult_with_num = decltype(std::declval<value_type>() * std::declval<OtherNum>());
template <typename OtherVal>
using value_type_when_mult_with_val = value_type_when_mult_with_num<typename OtherVal::value_type>;
template <typename OtherNum>
using value_type_when_div_by_num = decltype(std::declval<value_type>() * std::declval<OtherNum>());
template <typename OtherVal>
using value_type_when_div_by_val = value_type_when_div_by_num<typename OtherVal::value_type>;
template <typename OtherNum>
using multiply_by_num = val<unit_list_type, value_type_when_mult_with_num<OtherNum>>;
template <typename OtherVal>
using multiply_by_val = val<
product<unit_list_type, typename OtherVal::unit_list_type>,
value_type_when_mult_with_val<OtherVal>
>;
template <typename OtherNum>
using divide_by_num = val<unit_list_type, value_type_when_div_by_num<OtherNum>>;
template <typename OtherVal>
using divide_by_val = val<
rate<unit_list_type, typename OtherVal::unit_list_type>,
value_type_when_div_by_val<OtherVal>
>;
public:
constexpr val(value_type value) : value(value) {}
template <
typename OtherVal,
typename Converter = detail::find_unit_conversion<typename OtherVal::unit_list_type, unit_list_type>,
typename std::enable_if<Converter::could_convert>::type* = nullptr
>
constexpr val(const OtherVal& other) : value(Converter::type::convert(other.value)) {}
template <typename OtherVal, typename std::enable_if<detail::is_val<OtherVal>::value>::type* = nullptr>
constexpr auto operator*(const OtherVal& other) const -> multiply_by_val<OtherVal> {
return multiply_by_val<OtherVal>(this->value * other.value);
}
template <typename OtherNum, typename std::enable_if<std::is_arithmetic<OtherNum>::value>::type* = nullptr>
constexpr auto operator*(const OtherNum& other) const -> multiply_by_num<OtherNum> {
return val<unit_list_type>(this->value * other);
}
template <typename OtherVal, typename std::enable_if<detail::is_val<OtherVal>::value>::type* = nullptr>
constexpr auto operator/(const OtherVal& other) const -> divide_by_val<OtherVal> {
return divide_by_val<OtherVal>(this->value / other.value);
}
template <typename OtherNum, typename std::enable_if<std::is_arithmetic<OtherNum>::value>::type* = nullptr>
constexpr auto operator/(const OtherNum& other) const -> divide_by_num<OtherNum> {
return divide_by_num<OtherNum>(this->value / other);
}
value_type value;
};
}
struct seconds {};
struct meters {};
struct kilograms {};
struct feet {};
namespace sdim {
template <>
struct unit_conversion<meters, feet> {
constexpr static auto conversion_factor = 3.280839895;
};
}
int main() {
using namespace sdim;
val<seconds> time(10);
val<meters> distance(5);
val<kilograms> mass(100);
val<rate<meters, seconds>> speed = distance / time;
val<rate<meters, power<seconds, 2>>> acceleration = speed / time;
val<product<kilograms, rate<power<meters, 2>, power<seconds, 2>>>> energy = mass * distance * acceleration;
val<product<power<meters, 2>, power<seconds, -2>, power<kilograms, 1>>> alt_energy = energy;
//val<product<power<meters, 1>, power<seconds, -2>, power<kilograms, 1>>> will_not_compile = energy;
val<feet> distance_ft (25);
val<meters> distance_m = distance_m;
val<meters> times_scalar = distance_m * 2;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment