Skip to content

Instantly share code, notes, and snippets.

@kuhar
Created January 9, 2015 19:27
Show Gist options
  • Save kuhar/baaf11bafba4907a2fd4 to your computer and use it in GitHub Desktop.
Save kuhar/baaf11bafba4907a2fd4 to your computer and use it in GitHub Desktop.
compile-time fixed-point
#include <ratio>
template <char... Ts>
struct seq;
template <class Seq>
struct parse_sign
{
static constexpr auto sign = intmax_t{1};
using tail = Seq;
};
template <char... Ts>
struct parse_sign<seq<'+', Ts...>>
{
static constexpr auto sign = intmax_t{1};
using tail = seq<Ts...>;
};
template <char... Ts>
struct parse_sign<seq<'-', Ts...>>
{
static constexpr auto sign = intmax_t{-1};
using tail = seq<Ts...>;
};
template <bool BeforePoint, intmax_t Num, intmax_t Den, class Seq>
struct parse_frac;
template <bool BeforePoint, intmax_t Num, intmax_t Den>
struct parse_frac<BeforePoint, Num, Den, seq<>>
{
static constexpr auto num = Num;
static constexpr auto den = Den;
};
template <intmax_t Num, intmax_t Den, char... Ts>
struct parse_frac<true, Num, Den, seq<'.', Ts...>>
{
using next = parse_frac<false, Num, Den, seq<Ts...>>;
static constexpr auto num = next::num;
static constexpr auto den = next::den;
};
template <intmax_t Num, intmax_t Den, char T, char... Ts>
struct parse_frac<true, Num, Den, seq<T, Ts...>>
{
static_assert(
T >= '0' && T <= '9',
"Expected digit."
);
using next = parse_frac<true, 10 * Num + (T - '0'), Den, seq<Ts...>>;
static constexpr auto num = next::num;
static constexpr auto den = next::den;
};
template <intmax_t Num, intmax_t Den, char T, char... Ts>
struct parse_frac<false, Num, Den, seq<T, Ts...>>
{
static_assert(
T >= '0' && T <= '9',
"Expected digit."
);
using next = parse_frac<false, 10 * Num + (T - '0'), 10 * Den, seq<Ts...>>;
static constexpr auto num = next::num;
static constexpr auto den = next::den;
};
template <class Char, Char... Ts>
constexpr auto operator"" _f()
{
using sign_parser = parse_sign<seq<Ts...>>;
using tail = typename sign_parser::tail;
using frac_parser = parse_frac<true, 0, 1, tail>;
return std::ratio<
sign_parser::sign * frac_parser::num,
frac_parser::den
>{};
}
#define cc_fixed(x) decltype(#x ## _f)
int main()
{
using x = cc_fixed(123.456);
using y = cc_fixed(+123.456);
using z = cc_fixed(-123.456);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment