int main() { return 0; }
#include <iostream>
#pragma mark Definition: Boolean
struct True { };
struct False { };
#pragma mark Definition: Equality
namespace {
template <typename, typename>
struct eq_impl { using type = False; };
template <typename A>
struct eq_impl<A, A> { using type = True; };
};
template <typename A, typename B>
using Equal = typename eq_impl<A, B>::type;
#pragma mark Definition: Natural Number
struct Zero {};
template <typename>
struct S {};
template <typename>
struct Eval;
template <>
struct Eval<Zero> {
static constexpr int value = 0;
};
template <typename Num>
struct Eval<S<Num>> {
static constexpr int value = 1 + Eval<Num>::value;
};
std::ostream &operator<<(std::ostream &os, const Zero &) {
os << Eval<Zero>::value;
return os;
}
template <typename Num>
std::ostream &operator<<(std::ostream &os, const S<Num> &) {
os << Eval<S<Num>>::value;
return os;
}
#pragma mark Definition: If
namespace {
template <typename Condition, typename Then, typename Else>
struct if_impl;
template <typename Then, typename Else>
struct if_impl<True, Then, Else> {
using type = Then;
};
template <typename Then, typename Else>
struct if_impl<False, Then, Else> {
using type = Else;
};
};
template <typename Condition, typename Then, typename Else>
using If = typename if_impl<Condition, Then, Else>::type;
#pragma mark Definition: Or
namespace {
template <typename, typename>
struct or_impl {
using type = True;
};
template <>
struct or_impl<False, False> {
using type = False;
};
};
template <typename P, typename Q>
using Or = typename or_impl<P, Q>::type;
#pragma mark Utility
namespace {
template <int n>
struct make_num_impl {
using type = S<typename make_num_impl<n - 1>::type>;
};
template <>
struct make_num_impl<0> {
using type = Zero;
};
};
template <int n>
using MakeNum = typename make_num_impl<n>::type;
struct Stop {};
struct Nothing {};
std::ostream &operator<<(std::ostream &os, const Nothing *) { return os; };
struct LineBreak { LineBreak() { std::cout << std::endl; } };
template <typename X, typename Y, typename T>
using Enable = If<Equal<X, Y>, Stop, T>;
#pragma mark Implementation of Fizz / Buzz
#define DefineFizzBuzz(Name, ...)\
template <typename Num, typename C = Zero> struct Name;\
template <typename Num, typename C> struct Name<S<Num>, C> : public Name<Num, If<Equal<C, __VA_ARGS__>, Zero, S<C>>> {};\
template <typename C> struct Name<Zero, C> { using is_enable = Equal<C, Zero>;\
Name() { std::cout << static_cast<If<is_enable, Name, Nothing> *>(nullptr); };\
};\
template <typename Num, typename C> std::ostream &operator<<(std::ostream &os, const Name<Num, C> *) {\
os << #Name;\
return os;\
};
DefineFizzBuzz(Fizz, S<S<Zero>>);
DefineFizzBuzz(Buzz, S<S<S<S<Zero>>>>);
#pragma mark Implementation of Number
template <typename> struct number_impl;
template <typename Num>
struct number_impl {
number_impl() { std::cout << Num(); }
};
template <typename Num>
using Number = If<Or<typename Fizz<Num>::is_enable, typename Buzz<Num>::is_enable>, Nothing, number_impl<Num>>;
#pragma mark FizzBuzz Composition
template <typename Num, typename Max>
struct fizz_buzz_impl : public
Fizz<Num>
, Buzz<Num>
, Number<Num>
, LineBreak
, Enable<Num, Max, fizz_buzz_impl<S<Num>, Max>> { };
template <int n>
using FizzBuzz = fizz_buzz_impl<S<Zero>, MakeNum<n>>;
FizzBuzz<100> fizzbuzz;
(ideoneのC++4.9.2とかC++14だと動かない!)
ideone
(FizzBuzz<100>
だと動かないけど FizzBuzz<20>
くらいなら動いた)