Last active
August 6, 2017 22:11
-
-
Save LordAro/60505eb8e5f121c3fac8a4b8c583c573 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
#include <array> | |
#include <tuple> | |
#include <type_traits> | |
#include <utility> | |
template<size_t c, class... Vars> | |
struct ForLoop { | |
template<template <size_t, class...> class Func> | |
static void iterate() { | |
ForLoop<c-1, Vars...>::template iterate<Func>(); | |
Func<c, Vars...>()(); | |
} | |
}; | |
template<class... Vars> | |
struct ForLoop<1, Vars...> { | |
template<template <size_t, class...> class Func> | |
static void iterate() { | |
Func<1, Vars...>()(); | |
} | |
}; | |
// Strings | |
class str_const { | |
private: | |
const char* const p_; | |
const std::size_t sz_; | |
public: | |
template<std::size_t N> | |
constexpr str_const(const char(&a)[N]) : p_(a), sz_(N-1) {} | |
constexpr char operator[](std::size_t n) const { | |
return n < sz_ ? p_[n] : throw std::out_of_range(""); | |
} | |
constexpr std::size_t size() const { | |
return sz_; | |
} | |
}; | |
template <char... letters> | |
struct to_chars { | |
static constexpr char value[] = {letters..., '\0'}; | |
}; | |
template<str_const const& str, std::size_t... I> | |
auto constexpr expand(std::index_sequence<I...>) { | |
return to_chars<str[I]...>{}; | |
} | |
// Pair of string and divisor | |
template<str_const const& str, size_t div> | |
using fizzbuzz_to_type = std::pair<decltype(expand<str>(std::make_index_sequence<str.size()>{})), std::integral_constant<std::size_t, div>>; | |
template <size_t N, typename... buzzes> | |
struct FizzBuzz { | |
static constexpr bool does_divide_any() { | |
bool result = false; // Horrifying abuse of initializer_list to make up for the lack of folds in C++14 | |
(void)std::initializer_list<int>{ (result = result || (N % buzzes::second_type::value == 0), 0)... }; | |
return result; | |
} | |
template <class fizz> | |
std::enable_if_t<N % fizz::second_type::value == 0> | |
recursivePrint() { // base | |
printf("%s", fizz::first_type::value); | |
} | |
template <class fizz> | |
std::enable_if_t<N % fizz::second_type::value != 0> | |
recursivePrint() {} | |
template <class fizz, class buzz, class... remaining> | |
void recursivePrint() { | |
recursivePrint<fizz>(); | |
recursivePrint<buzz, remaining...>(); | |
} | |
template <typename T = void> | |
std::enable_if_t<does_divide_any(), T> | |
operator()() { | |
recursivePrint<buzzes...>(); | |
printf("\n"); | |
} | |
template <typename T = void> | |
std::enable_if_t<!does_divide_any(), T> | |
operator()() { | |
printf("%lu\n", N); | |
} | |
}; | |
// To add more buzz types, just add the string and its associated divisor below, and to the list in main | |
constexpr str_const fizz{"Fizz"}; | |
constexpr str_const buzz{"Buzz"}; | |
using fizz_t = fizzbuzz_to_type<fizz, 3>; | |
using buzz_t = fizzbuzz_to_type<buzz, 5>; | |
int main() | |
{ | |
ForLoop<100, fizz_t, buzz_t>::iterate<FizzBuzz>(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment