331.md

May 29, 2023 · View on GitHub

Info

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>’

https://godbolt.org/z/bj88jMWfW

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]);

https://godbolt.org/z/3YvfqezPa

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>()...};

https://godbolt.org/z/Yq9xdYo3a

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>();

https://godbolt.org/z/Gcx4sd5E3

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>{});

https://godbolt.org/z/bdjEadn5f