106
I've found the recent typescript 3x3 magic square checker entertaining. Anyway here is a arbitrary magic square checker using c++ type traits.
(cdn.imgchest.com)
alt
#include <type_traits>
// from https://stackoverflow.com/a/8625010/12469275
// cmath's sqrt is constexpr from c++26
constexpr std::size_t isqrt_impl
(std::size_t sq, std::size_t dlt, std::size_t value){
return sq <= value ?
isqrt_impl(sq+dlt, dlt+2, value) : (dlt >> 1) - 1;
}
constexpr std::size_t isqrt(std::size_t value){
return isqrt_impl(1, 3, value);
}
// because pack indexing is only in c++26
template <std::size_t I, typename T = void, std::size_t... V>
struct At;
template <std::size_t I>
struct At<I, void> {};
template <std::size_t V0, std::size_t... V>
struct At<0, void, V0, V...> {
static const std::size_t value = V0;
};
template <std::size_t I, std::size_t V0, std::size_t... V>
struct At<I, std::enable_if_t<I != 0 && I <= sizeof...(V),void>, V0, V...> {
static const std::size_t value = At<I-1, void, V...>::value;
};
template <std::size_t A, std::size_t B>
struct Add {
static const std::size_t value = A + B;
};
template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t A, std::size_t B> typename R, std::size_t I, typename _, std::size_t... V>
struct _ReduceFor;
template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t A, std::size_t B> typename R, std::size_t I, std::size_t... V>
struct _ReduceFor<begin, end, step, R, I, std::enable_if_t<(begin < end),void>, V...> {
typedef R<At<begin,void, V...>::value,_ReduceFor<begin+step, end, step, R, I, void, V...>::type::value> type;
};
template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t A, std::size_t B> typename R, std::size_t I, std::size_t... V>
struct _ReduceFor<begin, end, step, R, I, std::enable_if_t<(begin >= end), void>, V...> {
typedef std::integral_constant<std::size_t,I> type;
};
template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t A, std::size_t B> typename R, std::size_t I, std::size_t... V>
using ReduceFor = _ReduceFor<begin,end,step,R,I,void,V...>;
template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t I, typename T> typename V, typename T, typename _>
struct AllFor;
template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t I, typename T> typename V, typename T>
struct AllFor<begin, end, step, V, T, std::enable_if_t<(begin < end), void>> {
typedef std::enable_if_t<std::is_same<typename V<begin, bool>::type, bool>::value, typename AllFor<begin+step, end, step, V, T, void>::type> type;
};
template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t I, typename T> typename V, typename T>
struct AllFor<begin, end, step, V, T, std::enable_if_t<(begin >= end), void>> {
typedef T type;
};
template <std::size_t begin, std::size_t end, std::size_t step, template<std::size_t I, typename T> typename V, typename T>
using AllFor_t = typename AllFor<begin, end, step, V, T, void>::type;
template <std::size_t S, typename T, std::size_t... V>
struct ValidRows {
template <std::size_t I, typename T2>
struct Inner {
typedef std::enable_if_t<ReduceFor<I, I+S, 1, Add, 0, V...>::type::value == S * (S*S + 1)/2, T2> type;
};
typedef AllFor_t<0, S*S, S, Inner, T> type;
};
template <std::size_t S, typename T, std::size_t... V>
struct ValidColumns {
template <std::size_t I, typename T2>
struct Inner {
typedef std::enable_if_t<ReduceFor<I, I+S*S, S, Add, 0, V...>::type::value == S * (S*S + 1)/2, T2> type;
};
typedef AllFor_t<0, S, 1, Inner, T> type;
};
template <std::size_t S, typename T, std::size_t... V>
struct ValidDiags {
typedef std::enable_if_t<ReduceFor<0,S*S,S+1,Add, 0, V...>::type::value == S * (S*S + 1)/2 && ReduceFor<S-1,S*S-1,S-1,Add, 0, V...>::type::value == S * (S*S + 1)/2, T> type;
};
template <typename T, std::size_t... V>
struct Unique;
template <typename T, std::size_t N, std::size_t... V>
struct Unique<T,N,V...> {
template <std::size_t I, typename T2>
struct Inner {
typedef std::enable_if_t<N != At<I,void,V...>::value,T2> type;
};
typedef AllFor_t<0,sizeof...(V),1,Inner,T> type;
};
template <typename T, std::size_t V>
struct Unique<T, V> {
typedef T type;
};
template <typename T, std::size_t... V>
struct InRange {
template <std::size_t I, typename T2>
struct Inner {
typedef typename std::enable_if<1 <= At<I,void, V...>::value && At<I,void,V...>::value <= sizeof...(V), T2>::type type;
};
typedef AllFor_t<0,sizeof...(V),1,Inner,T> type;
};
template <typename T, std::size_t... V>
struct Grid {
static const std::size_t S = isqrt(sizeof...(V));
typedef std::enable_if_t<S*S == sizeof...(V), typename ValidRows<S, typename ValidColumns<S, typename ValidDiags<S, typename Unique<typename InRange<T,V...>::type, V...>::type, V...>::type, V...>::type, V...>::type> type;
};
using ok = Grid<void,
2, 7, 6,
9, 5, 1,
4, 3, 8>::type;
int main() {}
I specifically used https://carbon.now.sh