// Copyright © 2017 Martin Ueding <dev@martin-ueding.de>
// Licensed under the MIT/Expat license.

#include <iostream>

template <int i, bool divisable_3, bool divisable_5>
struct FizzBuzz_1 {
    static int const value = i;
};

template <int i>
struct FizzBuzz_1<i, true, false> {
    static int const value = -1;
};

template <int i>
struct FizzBuzz_1<i, false, true> {
    static int const value = -2;
};

template <int i>
struct FizzBuzz_1<i, true, true> {
    static int const value = -3;
};

template <int i>
struct FizzBuzz : public FizzBuzz_1<i, i % 3 == 0, i % 5 == 0> {};

template <int i>
constexpr char const *word();

template <>
constexpr char const *word<-1>() {
    return "Fizz";
}

template <>
constexpr char const *word<-2>() {
    return "Buzz";
}

template <>
constexpr char const *word<-3>() {
    return "FizzBuzz";
}

template <int i>
struct Print {
    static void print() {
        Print<i - 1>::print();
        auto const value = FizzBuzz<i>::value;
        if (value < 0) {
            std::cout << word<value>() << std::endl;
        } else {
            std::cout << value << std::endl;
        }
    }
};

template <>
struct Print<0> {
    static void print() {}
};

int main() {
    Print<100>::print();
}
