Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement STL functions in variadic template

I have been working on a small project to get up to speed with variadic templates. I implemented a small multidimensional array. I would now like to define a function that operates on the nearest neighbours of a given position -- is there an elegant way to retrieve the values of the neighbours of a given position in my array?

template<class T, size_t size, size_t... sizes>
struct MArr {
    typedef std::array<typename MArr<T, sizes...>::type, size> type;

    std::array<MArr<T, sizes...>,size> data;

    MArr<T, sizes...>& operator[](int i) {
        return data[i];
    }

};

template<class T, size_t size>
struct MArr<T, size> {
    typedef std::array<T, size> type;
    type data;

    T& operator[](int i) {
       return data[i];
    }

};

Addendum: It is somewhat clear to me how to loop all elements by employing recursion, e.g. applying an arbitrary function to a hyperdim. array of ints:

template <typename T, size_t size>
void func(MArr<T, size>& arr, std::function<void(int &)> f) {
    for (int i = 0; i < size; i++) {
       f(arr[i]);
    }
}


template <typename T, size_t size0, size_t size1, size_t ...sizes>
void func(MArr<T, size0, size1, sizes...>& arr, std::function<void(int &)> f) {
    for (int i =0; i < size0; i++) {
        func<T, size1, sizes...>(arr[i], f);
    }
}

I am curious how I would generate something like func(arr[i+1,j,k,…],arr[i-1,j,k,…],arr[i,j+1,k,…],arr[i,j-1,k,…],…) and a given func (which, say adds the respective elements). As I said, quite new to variadic templates and I have the feeling I don't have the right mindset yet …

like image 314
Faser Avatar asked Mar 08 '23 06:03

Faser


1 Answers

You may do something like (code use folding expression from C++17, but can be written in C++11):

template <std::size_t I, typename F, std::size_t ... Is, typename Tuple>
void helper(F&& f, std::index_sequence<Is...>, const Tuple& t)
{
    f((std::get<Is>(t) - (Is == I))...);
    f((std::get<Is>(t) + (Is == I))...);
}

template <typename F, std::size_t ... Is, typename Tuple>
void helper(F&& f, std::index_sequence<Is...> Seq, const Tuple& t)
{
    (helper<Is>(std::forward<F>(f), Seq, t), ...);
}

template <typename F, typename ... Ts>
void apply_to_neighboor(F&& f, Ts... indexes)
{
    helper(std::forward<F>(f), std::index_sequence_for<Ts...>(), std::tie(indexes...));
}

Demo

If you want to retrieve all neighbours, you might change above code to:

template <std::size_t I, std::size_t ... Is, typename Tuple>
auto helper1(std::index_sequence<Is...>, const Tuple& t)
{
    return std::make_pair(std::make_tuple((std::get<Is>(t) - (Is == I))...),
                          std::make_tuple((std::get<Is>(t) + (Is == I))...));
}

template <std::size_t ... Is, typename Tuple>
auto helper(std::index_sequence<Is...> Seq, const Tuple& t)
{
    return std::tuple_cat(helper1<Is>(Seq, t)...);
}

template <typename F, typename ... Ts>
void apply_to_neighboor(F&& f, Ts... indexes)
{
    std::apply(std::forward<F>(f),
               helper(std::index_sequence_for<Ts...>(), std::tie(indexes...)));
}

Demo

like image 145
Jarod42 Avatar answered Mar 17 '23 09:03

Jarod42