Info
-
Did you know that
sizeof
operator can be used for efficient math computation?
Example
template<auto n> consteval auto sqr() {
return sizeof(std::byte[n][n]);
}
static_assert(2*2 == sqr<2>());
static_assert(10*10 == sqr<10>());
Puzzle
- Can you implement an
exponent
variable template which calculates the {x^n} only by leveragingsizeof
operator?
template<auto X, auto N>
constexpr auto exponent = 0;
static_assert(1 == exponent<1, 1>);
static_assert(1*1*1*1 == exponent<1, 4>);
static_assert(2*2 == exponent<2, 2>);
static_assert(4*4 == exponent<4, 2>);
static_assert(5*5*5*5 == exponent<5, 4>);
static_assert(10*10*10 == exponent<10, 3>);
static_assert(0 != exponent<1, 2>);
static_assert(1 != exponent<2, 1>);
static_assert(2 != exponent<2, 2>);
Solutions
template<auto X, auto N>
constexpr auto dimensions(auto x) {
if constexpr (N == 0) {
return x;
} else {
return dimensions<X,N-1>(std::array<decltype(x), X>{});
}
}
template<auto X, auto N>
constexpr auto exponent = sizeof(decltype(dimensions<X,N>(std::byte{})));
template <auto X, auto Y>
constexpr auto mult = sizeof(char[X][Y]);
template<auto X, auto N>
constexpr auto exponent = ((N & 1) == 0) ? mult<exponent<X, N/2>, exponent<X, N/2>> : mult<X, exponent<X, N-1>>;
template<auto X>
constexpr auto exponent<X, 0> = 1;
template<auto X, auto N>
constexpr auto exponent = sizeof( char[N % 2 ? X : 1][exponent<X, N / 2>][exponent<X, N / 2>] );
template<auto X>
constexpr auto exponent<X, 0> = 1;
template<size_t x, size_t n>
constexpr auto carr() {
if constexpr(n==0)
return std::array<char, 1>{};
else
return std::array< decltype(carr<x,n-1>()) , x>{};
}
template<auto x, auto n>
constexpr auto exponent = sizeof(carr<x,n>());
namespace detail {
template <auto Val>
[[nodiscard]] consteval auto mult() {
return Val;
}
template <auto Val1, auto Val2, auto... Vals>
[[nodiscard]] consteval auto mult() {
return mult<sizeof(std::byte[Val1][Val2]), Vals...>();
}
[[nodiscard]] consteval auto only_first(auto first, auto...) {
return first;
}
template <auto Base, auto... PowerSequence>
[[nodiscard]] consteval auto exponent_impl(std::index_sequence<PowerSequence...>) {
return mult<only_first(Base, PowerSequence)...>();
};
} // namespace detail
template <auto X, auto N>
constexpr auto exponent =
detail::exponent_impl<X>(std::make_index_sequence<N>{});
template<class T, auto N, class U>
consteval auto operator,(std::array<T, N>, U) { return std::array<U, N>{}; }
template<auto X, auto N>
constexpr auto exponent = []<auto... Ns>(std::index_sequence<Ns...>){
return sizeof((std::array<std::byte, (Ns, X)>{}, ...));
}(std::make_index_sequence<N>{});