Skip to content

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

Fizz Buzz Problem in c++ :

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 jamfile

jamroot

exe fizz : fizz-buzz.cpp : : <cxxstd>20 ;

 

 

 

Trackbacks

No Trackbacks

Comments

Display comments as Linear | Threaded

No comments

Add Comment

E-Mail addresses will not be displayed and will only be used for E-Mail notifications.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Form options

Submitted comments will be subject to moderation before being displayed.

@cppfx.xyz