Last active
September 30, 2023 10:10
-
-
Save shouth/a8792ae15ec7775e009f715f80b6e5d1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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