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 …
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With