Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function that can take arrays with different dimensions

Is there a method to create a single function that can take any dimension of vector without overloading?

Currently I have,

someFunction(vector<int> a)
someFunction(vector<vector<int> > a)
someFunction(vector<vector<vector<int> > > a)

However, would it be possible to have a function:

singleFunction(<n-dimension vector>)
{
    // Get dimension of array/vector
}
like image 828
J Sherratt Avatar asked Dec 17 '22 22:12

J Sherratt


2 Answers

You can use a recursive template function

#include <iostream>
#include <vector>

void func(int el) {
  std::cout << el << std::endl;
}

template<typename T>
void func(std::vector<T> v) {
  for (const T& el : v) {
    func(el);
  }
}

int main() {
  std::vector<std::vector<int>> v {{1, 2}, {2, 3}};
  func(v);
  return 0;
}

It's calling it itself for each element until it reaches elements of type int.

To get the dimension you can use the same pattern:

#include <iostream>
#include <vector>

template<typename T>
int someFunction(std::vector<T> v, int dim = 1);

template<>
int someFunction(std::vector<int> v, int dim) {
  return dim;
}

template<typename T>
int someFunction(std::vector<T> v, int dim) {
  return someFunction(T(), dim + 1);
}

template<typename T>
void singleFunction(std::vector<T> v) {
  int dim(someFunction(v));
  std::cout << dim << std::endl;
  // Do something
}

int main() {
  std::vector<std::vector<std::vector<int>>> v {{{1, 0}, {2, 4}}, {{2, 2}, {3, 0}}};
  singleFunction(v);
  singleFunction(std::vector<std::vector<int>>());
  singleFunction(std::vector<int>());
  return 0;
}

Here it creates a new object of value type and calls itself until its value type is int. Every time it increments the dimension.

like image 199
Thomas Sablik Avatar answered Dec 24 '22 02:12

Thomas Sablik


Perhaps you could try this approach, I think this is exactly what you are asking (adopted from std::rank):

#include <iostream>
#include <vector>
#include <type_traits>

template<typename T>
struct vector_rank : public std::integral_constant<std::size_t, 0> {};

template<typename T>
struct vector_rank<std::vector<T>> : public std::integral_constant<std::size_t, vector_rank<T>::value + 1> {};

template<typename T>
size_t GetVectorRank(T)
{
    return vector_rank<T>::value;
}

int main()
{
    std::vector<std::vector<std::vector<std::vector<std::vector<int>>>>> v1;
    std::cout << GetVectorRank(v1) << std::endl;
    std::vector<std::vector<std::vector<int>>> v2;
    std::cout << GetVectorRank(v2) << std::endl;
    return 0;
}

The second template be selected recursively while the type is std::vector<T>, the first template will be selected for everything else as well as at the end of recursion. The above example will return:

5
3

Demo: https://ideone.com/CLucGA

like image 32
Killzone Kid Avatar answered Dec 24 '22 02:12

Killzone Kid