Fizz Buzz c++/cpp Template Meta Programming Way
Template Meta Programming
Template metaprogramming is a set of c++ skills that the computations are done at compile time, aka the c++ compilers take our code and do computing. The c++ template is turing-complete if we do not limit the template recurring depth. We limit the template recurring depth because we do not want to let the compiling run into infinite loop.
Fizz Buzz Problem
Read previous: https://cppfx.xyz/index.php?/archives/66-Fizz-Buzz-c++cpp.html
Fizz Buzz: Count from 1 to 100, if the number can be divided by 3, return fizz; if the number can be divided by 5, return buzz; if the number can be divided by both 3 and 5, return fizz buzz; otherwise return the number.
Program Running Output:1 2 fizz 4 buzz fizz 7 8 fizz buzz 11 fizz 13 14 fizz-buzz 16 17 fizz 19 buzz fizz 22 23 fizz buzz 26 fizz 28 29 fizz-buzz 31 32 fizz 34 buzz fizz 37 38 fizz buzz 41 fizz 43 44 fizz-buzz 46 47 fizz 49 buzz fizz 52 53 fizz buzz 56 fizz 58 59 fizz-buzz 61 62 fizz 64 buzz fizz 67 68 fizz buzz 71 fizz 73 74 fizz-buzz 76 77 fizz 79 buzz fizz 82 83 fizz buzz 86 fizz 88 89 fizz-buzz 91 92 fizz 94 buzz fizz 97 98 fizz buzz
The template meta c++ code to fizz buzz problem
• fizz_buzz_number<number<value>>
The program stores types representing numbers from 1~100; if the number is fizz(divided by 3), stores fizz; if the number is buzz(divided by 5), stores buzz; if the number is fizz-buzz(divided by 15), stores fizz-buzz.
I make a class fizz_buzz_number, and a class number to represent if it is fizz, buzz, fizz-buzz, or number.
• create_tuple
create_tuple: This class takes a value of [1,100], and make a type fizz_buzz_number<number<value>>, then transfer the value-1 and the type as template parameter to next create_tuple.
When the last partial specialized template class create_tuple is called (aka when the value achieves 0), the template parameters of that create_tuple will hold all number types of fizz_buzz_number, so it can use all of them to create a tuple.
So, at last, we can take the final tuple from the class create_tuple.
• The Complete Code: fizz-bzz.cpp// Fizz Buzz c++/cpp #include <iostream> #include <tuple> // std::tuple, std::apply template <typename T> concept number_k = std::integral<std::decay_t<decltype(T::value)>>; template <typename T> concept fizz_k = number_k<T> && requires { requires T::value%3==0; }; template <typename T> concept buzz_k = number_k<T> && requires { requires T::value%5==0; }; template <typename T> concept fizz_buzz_k = fizz_k<T> && buzz_k<T>; // Define number type: convert a number value to a type. template <std::integral auto _value> class number { public: constexpr static auto value = _value; }; // Declare class fizz_buzz_number: fizz or buzz or number template <typename T> class fizz_buzz_number; // Define class fizz_buzz_number and how we print them. template <fizz_buzz_k T> class fizz_buzz_number<T> { public: friend std::ostream & operator<<(std::ostream & out, const fizz_buzz_number<T> &) { return out << "fizz-buzz"; } }; template <fizz_k T> class fizz_buzz_number<T> { public: friend std::ostream & operator<<(std::ostream & out, const fizz_buzz_number<T> &) { return out << "fizz"; } }; template <buzz_k T> class fizz_buzz_number<T> { public: friend std::ostream & operator<<(std::ostream & out, const fizz_buzz_number<T> &) { return out << "buzz"; } }; template <number_k T> class fizz_buzz_number<T> { public: friend std::ostream & operator<<(std::ostream & out, const fizz_buzz_number<T> &) { return out << T::value; } }; // type alias template <number_k T> using fbn = fizz_buzz_number<T>; // TL ... list: might be some type of fbn<number<value>> template <std::integral auto value, typename ... TL> class create_tuple { public: /* The trick is here: Add the current fizz_buzz_number type to the front of next create_tuple TL list. The last create_tuple will hold all template parameter list, so it will create the tuple with all number types. */ using tuple = typename create_tuple<value-1, fizz_buzz_number<number<value>>, TL ...>::tuple; }; // The last create_tuple: it will take all number types taken from // its previous create_tuple. template <typename ... TL> class create_tuple<0, TL ...> { public: using tuple = std::tuple<TL ...>; }; // Get the tuple type finally. template <std::integral auto value> using fbn_tuple = typename create_tuple<value>::tuple; int main() { // Print 1~100 fizz or buzz or number now. std::apply( [] (auto && ... elements) { ((std::cout << elements << ' '), ...); std::cout << '\n'; }, fbn_tuple<100>{} ); }
The code is tested running compiled by gcc and clang, with c++20 enabled.
b2 build jamfilejamroot
exe fizz : fizz-buzz.cpp : : <cxxstd>20 ;
Comments
Display comments as Linear | Threaded