Home > Enterprise >  C Compile time index/tuple access for tensor
C Compile time index/tuple access for tensor

Time:05-31

I have a compile time tensor class. Now i would like to implement index access like this:

std::array<std::array<std::array<int, 3>, 2>, 1> myTensor;

template <class... Indices>
auto get(Indices... indices) {
    return myTensor[indices][...];
}

int main() {
    myTensor[0][1][2] = 3;
    std::cout << get(0, 1, 2) << std::endl;
}

But this sadly does not compile. Does anyone have an idea of how i could implement this? It also needs to work when my tensor is const. I would also be fine using tuple instead of variadic template. I can use the most modern compiler/cpp standard if needed.

CodePudding user response:

You cannot fold over [] (for multidimensional indexing). You can achieve this with a pair of functions:

// This is written as generically as possible, but can be
// pared down by removing forwarding in your use case
template <class Container>
constexpr decltype(auto) get_of(Container&& c) noexcept {
    return std::forward<Container>(c);
}

template <class Container, class Index, class... Indices>
constexpr decltype(auto) get_of(Container&& c, Index&& index, Indices&&... indices) {
    return ::get_of(std::forward<Container>(c)[std::forward<Index>(index)], std::forward<Indices>(indices)...);
}

// Your attempt with `myTensor[indices][...]` becomes `get_of(myTensor, indices...)`
template <class... Indices>
decltype(auto) get(Indices... indices) {
    return get_of(myTensor, indices...);
}

And if you are using C 2b, you can use operator[] with multiple arguments, which might make it easier to use:

struct tensor_type {
    std::array<std::array<std::array<int, 3>, 2>, 1> myTensor;

    decltype(auto) operator[](auto... indices) {
        return get_of(myTensor, indices...);
    }
};

int main() {
    tensor_type t;
    t[0][1][2] = 3;
    std::cout << t[0, 1, 2] << '\n';
}

CodePudding user response:

You can use C 20 <ranges> to flatten a multidimensional array

#include <array>
#include <ranges>
#include <iostream>

std::array<std::array<std::array<int, 3>, 2>, 3> myTensor;

template <class... Indices>
auto& get(Indices... indices) {
  return (std::span(&myTensor, 1) |
    (std::views::transform(
      [&](auto& r) -> auto& { return r[indices];
    }) | ...))[0];
}

int main() {
  myTensor[0][1][2] = 3;
  myTensor[2][1][1] = 7;
  std::cout << get(0, 0, 0) << std::endl;
  std::cout << get(0, 1, 2) << std::endl;
  std::cout << get(2, 1, 1) << std::endl;
}

Demo

  • Related