Skip to content

Instantly share code, notes, and snippets.

@shouth
Last active September 30, 2023 10:10
Show Gist options
  • Save shouth/a8792ae15ec7775e009f715f80b6e5d1 to your computer and use it in GitHub Desktop.
Save shouth/a8792ae15ec7775e009f715f80b6e5d1 to your computer and use it in GitHub Desktop.
namespace shouth
{
struct Bool { };
struct True : public Bool { };
struct False : public Bool { };
namespace detail
{
template <typename A>
struct Not;
template <>
struct Not<True> {
using type = False;
};
template <>
struct Not<False> {
using type = True;
};
} // namespace detail
template <typename A>
using Not = typename detail::Not<A>::type;
namespace detail
{
template <typename A, typename B>
struct And;
template <>
struct And<True, True> {
using type = True;
};
template <>
struct And<True, False> {
using type = False;
};
template <>
struct And<False, True> {
using type = False;
};
template <>
struct And<False, False> {
using type = False;
};
} // namespace detail
template <typename A, typename B>
using And = typename detail::And<A, B>::type;
struct Natural { };
template <typename N>
struct Succesor : public Natural { };
namespace detail
{
template <typename N>
struct Predecessor;
template <typename N>
struct Predecessor<Succesor<N>> {
using type = N;
};
} // namespace detail
template <typename N>
using Predecessor = typename detail::Predecessor<N>::type;
struct _0 : public Natural { };
using _1 = Succesor<_0>;
using _2 = Succesor<_1>;
using _3 = Succesor<_2>;
using _4 = Succesor<_3>;
using _5 = Succesor<_4>;
using _6 = Succesor<_5>;
using _7 = Succesor<_6>;
using _8 = Succesor<_7>;
using _9 = Succesor<_8>;
using _10 = Succesor<_9>;
using _11 = Succesor<_10>;
using _12 = Succesor<_11>;
using _13 = Succesor<_12>;
using _14 = Succesor<_13>;
using _15 = Succesor<_14>;
using _16 = Succesor<_15>;
using _17 = Succesor<_16>;
using _18 = Succesor<_17>;
using _19 = Succesor<_18>;
using _20 = Succesor<_19>;
namespace detail
{
template <typename M, typename N>
struct Equal {
using type = False;
};
template <>
struct Equal<_0, _0> {
using type = True;
};
template <typename M, typename N>
struct Equal<Succesor<M>, Succesor<N>> {
using type = typename Equal<M, N>::type;
};
} // namespace detail
template <typename M, typename N>
using Equal = typename detail::Equal<M, N>::type;
namespace detail
{
template <typename M, typename N>
struct LessThan {
using type = False;
};
template <typename N>
struct LessThan<_0, Succesor<N>> {
using type = True;
};
template <typename M, typename N>
struct LessThan<Succesor<M>, Succesor<N>> {
using type = typename LessThan<M, N>::type;
};
}
template <typename M, typename N>
using LessThan = typename detail::LessThan<M, N>::type;
namespace detail
{
template <typename M, typename N>
struct Minus;
template <typename N>
struct Minus<N, _0> {
using type = N;
};
template <typename M, typename N>
struct Minus<M, Succesor<N>> {
using type = typename Predecessor<typename Minus<M, N>::type>::type;
};
} // namespace detail
template <typename M, typename N>
using Minus = typename detail::Minus<M, N>::type;
namespace detail
{
template <typename M, typename N, typename Where = True>
struct Modulo {
using type = typename Modulo<typename Minus<M, N>::type, N>::type;
};
template <typename M, typename N>
struct Modulo<M, N, typename LessThan<M, N>::type> {
using type = M;
};
} // namespace detail
template <typename M, typename N>
using Modulo = typename detail::Modulo<M, N>::type;
} // namespace shouth
struct Fizz { };
struct Buzz { };
struct FizzBuzz { };
namespace detail
{
template <typename M, typename N>
using DivisibleBy = shouth::Equal<shouth::Modulo<M, N>, shouth::_0>;
template <typename N, typename Where = shouth::True>
struct GetFizzBuzz {
using type = N;
};
template <typename N>
struct GetFizzBuzz<N, shouth::And<DivisibleBy<N, shouth::_3>, DivisibleBy<N, shouth::_5>>> {
using type = FizzBuzz;
};
template <typename N>
struct GetFizzBuzz<N, shouth::And<DivisibleBy<N, shouth::_3>, shouth::Not<DivisibleBy<N, shouth::_5>>>> {
using type = Fizz;
};
template <typename N>
struct GetFizzBuzz<N, shouth::And<shouth::Not<DivisibleBy<N, shouth::_3>>, DivisibleBy<N, shouth::_5>>> {
using type = Buzz;
};
} // namespace detail
template <typename N>
using GetFizzBuzz = typename detail::GetFizzBuzz<N>::type;
#include <iostream>
#include <type_traits>
auto main() -> int
{
using namespace shouth;
static_assert(std::is_same_v<GetFizzBuzz<_1>, _1>);
static_assert(std::is_same_v<GetFizzBuzz<_2>, _2>);
static_assert(std::is_same_v<GetFizzBuzz<_3>, Fizz>);
static_assert(std::is_same_v<GetFizzBuzz<_4>, _4>);
static_assert(std::is_same_v<GetFizzBuzz<_5>, Buzz>);
static_assert(std::is_same_v<GetFizzBuzz<_6>, Fizz>);
static_assert(std::is_same_v<GetFizzBuzz<_7>, _7>);
static_assert(std::is_same_v<GetFizzBuzz<_8>, _8>);
static_assert(std::is_same_v<GetFizzBuzz<_9>, Fizz>);
static_assert(std::is_same_v<GetFizzBuzz<_10>, Buzz>);
static_assert(std::is_same_v<GetFizzBuzz<_11>, _11>);
static_assert(std::is_same_v<GetFizzBuzz<_12>, Fizz>);
static_assert(std::is_same_v<GetFizzBuzz<_13>, _13>);
static_assert(std::is_same_v<GetFizzBuzz<_14>, _14>);
static_assert(std::is_same_v<GetFizzBuzz<_15>, FizzBuzz>);
static_assert(std::is_same_v<GetFizzBuzz<_16>, _16>);
static_assert(std::is_same_v<GetFizzBuzz<_17>, _17>);
static_assert(std::is_same_v<GetFizzBuzz<_18>, Fizz>);
static_assert(std::is_same_v<GetFizzBuzz<_19>, _19>);
static_assert(std::is_same_v<GetFizzBuzz<_20>, Buzz>);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment