Skip to content

Instantly share code, notes, and snippets.

@LordAro
Last active August 6, 2017 22:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LordAro/60505eb8e5f121c3fac8a4b8c583c573 to your computer and use it in GitHub Desktop.
Save LordAro/60505eb8e5f121c3fac8a4b8c583c573 to your computer and use it in GitHub Desktop.
#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