C ++编译时的Fizz-Buzz

时间:2017-08-24 18:01:55

标签: c++ gcc fizzbuzz

我们今天谈到了“fizz buzz”编程测试,我考虑过用C ++实现这个,但是使用元编程。理想情况下,它会在编译期间生成输出。

我当前的代码使用模板,但仍然必须执行才能生成输出。请在Ideone上查看。

我仍然使用std::cout <<来在屏幕上打印输出。 FizzBuzz<i>::value会提供i-1(Fizz),-2(Buzz)或-3(FizzBu​​zz)。然后为负数定义word<value>并给出char const *

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;
        }
    }
};

循环由于递归而消失,有一个Print<0>可以阻止它。

是否有某种方法可以打印word<value>()value,这些在编译期间在编译时是已知的?这可能不适用于每个编译器,因此我很满意与GCC和/或Clang一起使用的解决方案。

1 个答案:

答案 0 :(得分:2)

虽然可以通过一些模板技巧在编译时创建字符串,但在编译时打印它似乎并不合理。

这里是创建字符串的代码:

#include <iostream>
#include <type_traits>
#include <utility>

// Compile time string
template <char ...C> struct str_lit
{
    static constexpr char value[] {C..., '\0'};
};

// Integer to str_lit
constexpr std::size_t cexpr_pow(std::size_t x, std::size_t y)
{
    std::size_t ret = 1;
    while (y--)
        ret *= x;
    return ret;
}
template <std::size_t N, std::size_t X, typename = std::make_index_sequence<X>> struct num_to_sl_impl;
template <std::size_t N, std::size_t X, std::size_t ...Seq> struct num_to_sl_impl<N, X, std::index_sequence<Seq...>>
{
    static constexpr auto func()
    {
        if constexpr (N >= cexpr_pow(10,X))
            return num_to_sl_impl<N, X+1>::func();
        else
            return str_lit<(N / cexpr_pow(10,X-1-Seq) % 10 + '0')...>{};
    }
};
template <std::size_t N> using num_to_sl = decltype(num_to_sl_impl<N,1>::func());

// str_lit concatenation
template <typename F, typename ...P> struct sl_cat_impl {using type = typename sl_cat_impl<F, typename sl_cat_impl<P...>::type>::type;};
template <char ...C1, char ...C2> struct sl_cat_impl<str_lit<C1...>,str_lit<C2...>> {using type = str_lit<C1..., C2...>;};
template <typename F, typename ...P> using sl_cat = typename sl_cat_impl<F, P...>::type;

// The FizzBuzz
template <std::size_t N> struct fizzbuzz_impl
{
    using fizz = std::conditional_t<N % 3 == 0,
                                    str_lit<'f','i','z','z'>,
                                    str_lit<>>;
    using buzz = std::conditional_t<N % 5 == 0,
                                    str_lit<'b','u','z','z'>,
                                    str_lit<>>;
    using type = sl_cat<typename fizzbuzz_impl<N-1>::type,
                        std::conditional_t<N % 3 == 0 || N % 5 == 0,
                                           sl_cat<fizz, buzz>,
                                           num_to_sl<N>>,
                        str_lit<'\n'>>;
};
template <> struct fizzbuzz_impl<0>
{
    using type = str_lit<>;
};
template <std::size_t N> using fizzbuzz = typename fizzbuzz_impl<N>::type;

使用示例:

int main()
{
    std::cout << fizzbuzz<15>::value;
}

输出:

  

1
  2
  嘶嘶声
  4
  嗡嗡
  嘶嘶声
  7
  8
  嘶嘶声
  嗡嗡
  11个
  嘶嘶声
  13个
  14个
  fizzbuzz