Skip to content

Instantly share code, notes, and snippets.

@crosstyan
Last active July 26, 2023 07:21
Show Gist options
  • Save crosstyan/b52db5f69c9060e28ea9cd134caf5a49 to your computer and use it in GitHub Desktop.
Save crosstyan/b52db5f69c9060e28ea9cd134caf5a49 to your computer and use it in GitHub Desktop.
basically a variant of std::duration. C++20 is required since concept is used.
#include <cstddef>
#include <cstdint>
#include<format>
#include<chrono>
#include<concepts>
#include <ratio>
#include <type_traits>
#include<utility>
#include<iostream>
namespace utils {
template<typename T>
concept is_intmax_t = std::is_same_v<T, decltype(std::ratio<1>::num)&>;
template<typename T>
concept is_ratio = requires (T t){
{t.num} -> is_intmax_t;
{t.den} -> is_intmax_t;
};
template<class Rep, class RI = std::ratio<1>>
requires std::is_arithmetic_v<Rep> && is_ratio<RI>
class length {
Rep value;
public:
using rep = Rep;
using ratio = RI;
Rep count() const {
return value;
}
length() = default;
length(Rep v) : value(v) {}
};
template<class FromLength, class ToLength,
class RI = typename std::ratio_divide<typename FromLength::ratio, typename ToLength::ratio>::type>
struct __length_cast {
ToLength operator()(const FromLength& fl) const {
using _Ct = typename std::common_type<typename FromLength::rep, typename ToLength::rep, intmax_t>::type;
return ToLength(static_cast<typename ToLength::rep>(
static_cast<_Ct>(fl.count()) * static_cast<_Ct>(RI::num)
/ static_cast<_Ct>(RI::den)));
};
};
template <class ToLength, class Rep, class RI>
requires std::is_arithmetic_v<Rep> && is_ratio<RI>
ToLength length_cast(const length<Rep, RI>& fl){
return __length_cast<length<Rep, RI>, ToLength>()(fl);
}
using picometer = length<size_t, std::pico>;
using micrometer = length<size_t, std::micro>;
using milimeter = length<size_t, std::milli>;
using centimeter = length<size_t, std::centi>;
using meter = length<size_t, std::ratio<1>>;
using inch = length<size_t, std::ratio<254, 10000>>;
using feet = length<size_t, std::ratio<328, 1000>>;
// using inch = length<size_t, int>;
using kilometer = length<size_t, std::kilo>;
};
int main(){
auto m = utils::meter(1);
auto cm = utils::length_cast<utils::centimeter>(m);
auto mm = utils::length_cast<utils::milimeter>(m);
auto km = utils::length_cast<utils::length<float, std::kilo>>(m);
auto feet = utils::length_cast<utils::feet>(m);
auto inch = utils::length_cast<utils::inch>(m);
std::cout << std::format("m:\t{}\n", m.count());
std::cout << std::format("mm:\t{}\n", mm.count());
std::cout << std::format("cm:\t{}\n", cm.count());
std::cout << std::format("km:\t{}\n", km.count());
std::cout << std::format("feet:\t{}\n", feet.count());
std::cout << std::format("inch:\t{}\n", inch.count());
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment