#include <vector>
#include <iostream>
#include <algorithm>

namespace so {
using size = std::size_t;
using array_1d = std::vector<size>;
using array_2d = std::vector<array_1d>;

array_2d generate_combinations_all(array_1d const & _values_max) {
 array_2d values_all_; // arrays of all possible values for each position
 size count_combination_{1}; // number of possible combinations

 for (auto i_ : _values_max) { // generate & fill in 'values_all_'
  array_1d values_current_(i_);
  size value_current_{0};

  std::generate(values_current_.begin(), values_current_.end(), [&] {return (value_current_++);});
  values_all_.push_back(std::move(values_current_));
  count_combination_ *= i_;
 }

 array_2d combinations_all_; // array of arrays of all possible combinations
 array_1d indices_(_values_max.size(), 0); // array of current indices

 for (size i_{0}; i_ < count_combination_; ++i_) {
  array_1d combinantion_current_; // current combination

  for (size j_{0}; j_ < indices_.size(); ++j_) // fill in current combination
   combinantion_current_.push_back(values_all_[j_][indices_[j_]]);

  combinations_all_.push_back(std::move(combinantion_current_)); // append to 'combinations_all_'

  for (size m_{indices_.size()}; m_-- > 0;) // update current indices
   if (indices_[m_] < _values_max[m_] - 1) { // ++index at highest position possible
    ++indices_[m_];
    break;
   }
   else indices_[m_] = 0; // reset index if it's alrady at max value
 }

 return (combinations_all_);
}

void print_combinations_all(array_2d const & _combinations_all) {
 for (auto const & i_ : _combinations_all) { // "fancy" printing
  std::cout << "[";
  for (size j_{0}; j_ < i_.size(); ++j_)
   std::cout << i_[j_] << ((j_ < i_.size() - 1) ? ", " : "]\n");
 }
}
} // namespace so

int main() {
 so::array_1d values_max_a_{3, 2, 2};
 so::array_1d values_max_b_{2, 1, 3, 2};

 so::print_combinations_all(so::generate_combinations_all(values_max_a_));
 std::cout << "***************" << std::endl;
 so::print_combinations_all(so::generate_combinations_all(values_max_b_));

 return (0);
}
