#include <iomanip>
#include <iostream>

template<int...> struct IntegerSequence {
};

template<int n, class = IntegerSequence<>, bool = n == 0> struct MakeIntegerSequenceImpl;

template<int n, int... i>
struct MakeIntegerSequenceImpl<n, IntegerSequence<i...>, true> {
  typedef IntegerSequence<i...> type;
};

template<int n, int... i>
struct MakeIntegerSequenceImpl<n, IntegerSequence<i...>, false> {
  typedef typename MakeIntegerSequenceImpl<n - 1, IntegerSequence<n - 1, i...>>::type type;
};

template<int n>
using MakeIntegerSequence = typename MakeIntegerSequenceImpl<n>::type;

template<int n>
struct MultiplicationTableCell {
  static constexpr int value = ((n / 9) + 1) * ((n % 9) + 1);
};

template<class> struct MultiplicationTableImpl;

template<int... n>
struct MultiplicationTableImpl<IntegerSequence<n...>> {
  static const int value[];
};

template<int... n>
const int MultiplicationTableImpl<IntegerSequence<n...>>::value[] = {
  MultiplicationTableCell<n>::value...
};

struct MultiplicationTable : MultiplicationTableImpl<MakeIntegerSequence<81>> {
  static void print_twoLoops() {
    for (int i = 0; i < 9; ++i) {
      for (int j = 0; j < 9; ++j) {
        std::cout << std::setw(2) << value[(i * 9) + j] << ',';
      }
      std::cout << std::endl;
    }
  }

  static void print_oneLoop() {
    for (int i = 0; i < 81; ++i) {
      std::cout << std::setw(2) << value[i] << ',';
      if ((i % 9) == 8) {
        std::cout << std::endl;
      }
    }
  }

  static void print_noLoop_twoArgs(int i = 0, int j = 0) {
    if (i == 9) {
      return;
    }
    if (j == 9) {
      std::cout << std::endl;
      return print_noLoop_twoArgs(i + 1, 0);
    }
    std::cout << std::setw(2) << value[(i * 9) + j] << ',';
    print_noLoop_twoArgs(i, j + 1);
  }

  static void print_noLoop_oneArg(int i = 0) {
    if (i == 81) {
      return;
    }
    std::cout << std::setw(2) << value[i] << ',';
    if ((i % 9) == 8) {
      std::cout << std::endl;
    }
    print_noLoop_oneArg(i + 1);
  }
};

int main() {
  std::cout << "Use 'two' for loops:" << std::endl;
  MultiplicationTable::print_twoLoops();
  std::cout << std::endl;
  std::cout << "Use 'only one' for loop:" << std::endl;
  MultiplicationTable::print_oneLoop();
  std::cout << std::endl;
  std::cout << "Use 'no loops' (two arguments):" << std::endl;
  MultiplicationTable::print_noLoop_twoArgs();
  std::cout << std::endl;
  std::cout << "Use 'no loops' (one argument):" << std::endl;
  MultiplicationTable::print_noLoop_oneArg();
  return 0;
}
