#pragma once

#include <bitset>
#include <type_traits>


namespace detail {


template <typename ...>
struct List {};


template <typename ..._Terms> struct head_f;
template <typename ..._Terms> using Head = typename head_f<_Terms...>::value;

template <typename _Head, typename ..._Tail>
struct head_f<_Head, _Tail...> {
  using value = _Head;
};


} // namespace detail


template <typename ..._Terms>
struct Minterm {
  static_assert(
    (std::is_same_v<bool, typename _Terms::Result> && ...),
    "All Minterm Terms must have a Result type of bool"
  );
  using Operand = typename detail::Head<_Terms...>::Operand;
  using Value = std::bitset<sizeof...(_Terms)>;

  Value value;

  constexpr
  Minterm(Operand const &operand) {
    populate<0>(value, operand, detail::List<_Terms...>{});
  }

  template <std::size_t _bit, typename _Head, typename ..._Tail>
  constexpr
  void populate(Value &minterm, Operand const &operand, detail::List<_Head, _Tail...>) const {
    minterm[_bit] = _Head{}(operand);
    if constexpr (sizeof...(_Tail)) {
      populate<_bit + 1>(minterm, operand, detail::List<_Tail...>{});
    }
  }
};