331.md
May 29, 2023 · View on GitHub
Info
-
Did you about C++17 std::index_sequence, std::make_index_sequence?
Example
template <class...> struct whats_my_type;
int main() { whats_my_type<std::make_index_sequence<7>>{}; } // error: implicit instantiation of undefined template ‘whats_my_type<std::integer_sequence<unsigned long, 0, 1, 2, 3, 4, 5, 6>’<source>:8:3: error: implicit instantiation of undefined template ‘whats_my_type<std::integer_sequence<unsigned long, 0, 1, 2, 3, 4, 5, 6>’
Puzzle
- Can you generate - at compile time - a matrix (3x3) with values { true: if T.bar(id<X, Y>) is available, false: otherwise }?
template <auto...> struct id {};
struct Foo {
constexpr auto bar(id<0, 0>) {}
constexpr auto bar(id<1, 1>) {}
constexpr auto bar(id<2, 2>) {}
};
template <class T, auto N = 3>
constexpr const auto matrix; // TODO
// matrix<int, 3>:
// .long 1 # 0x1 // because Foo has bar(id<0, 0>)
// .long 0 # 0x0
// .long 0 # 0x0
// .long 0 # 0x0
// .long 1 # 0x1 // because Foo has bar(id<1, 1>)
// .long 0 # 0x0
// .long 0 # 0x0
// .long 0 # 0x0
// .long 1 # 0x1 // because Foo has bar(id<2, 2>)
static_assert(matrix<Foo>[0][0]);
static_assert(not matrix<Foo>[0][1]);
static_assert(not matrix<Foo>[0][2]);
static_assert(not matrix<Foo>[0][1]);
static_assert(matrix<Foo>[1][1]);
static_assert(not matrix<Foo>[2][1]);
static_assert(not matrix<Foo>[0][2]);
static_assert(not matrix<Foo>[1][2]);
static_assert(matrix<Foo>[2][2]);
Solutions
template <class T, std::size_t N = 3, class = std::make_index_sequence<N>>
constexpr const std::array<std::array<int, N>, N> matrix{};
template <class T, auto N, auto... Is>
constexpr const std::array matrix<T, N, std::index_sequence<Is...>>{
[]<auto I> -> std::array<int, 3> {
return {[]<auto J> -> int {
return requires(T v, id<I, J> p) { v.bar(p); };
}.template operator()<Is>()...};
}.template operator()<Is>()...};
template <class T, auto... ns>
constexpr auto has = []() { return requires(T t) { t.bar(id<ns...>{}); }; };
template <class T, auto R, auto N>
constexpr auto row = []() {
constexpr auto make_row =
[]<auto... I>(std::index_sequence<I...>) -> std::array<bool, N> {
return {has<T, R, I>()...};
};
return make_row(std::make_index_sequence<N>{});
};
template <class T, auto N>
constexpr auto rows = []() {
constexpr auto make_rows = []<auto... R>(std::index_sequence<R...>)
-> std::array<std::array<bool, N>, N> { return {row<T, R, N>()...}; };
return make_rows(std::make_index_sequence<N>{});
};
template <class T, auto N = 3>
constexpr const auto matrix = rows<T, N>();
template <typename T, auto N, auto X, auto C = X % N, auto R = (X - C) / N>
concept hasBar = requires(T t) {
{ t.bar(std::declval<id<R, C>>()) };
};
template <auto N, typename... Args>
constexpr std::array<std::array<long, N>, N> make_symmetric_matrix(
Args&&... args) {
return {std::forward<Args>(args)...};
}
template <class T, auto N = 3>
constexpr const auto matrix =
[]<auto... Indices>(std::index_sequence<Indices...>)
-> std::array<std::array<long, N>, N> {
return make_symmetric_matrix<N>(hasBar<T, N, static_cast<int>(Indices)>...);
}(std::make_index_sequence<N * N>{});