Reputation: 41
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
}
Upvotes: 4
Views: 166
Reputation: 16448
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.
Upvotes: 4
Reputation: 3047
you can get the dimension with this code
#include <vector>
#include <iostream>
template<unsigned N, typename T>
struct meta {
static unsigned func() {//terminale recursion case
return N;
}
};
template<unsigned N, typename T>
struct meta<N, std::vector<T> > {//mid recursion case
static unsigned func() {
return meta<N + 1, T>::func();
}
};
template<typename T>
unsigned func(T) { //adapter to deduce the type
return meta<0, T>::func();
}
int main() {
std::cout << func(std::vector<std::vector<std::vector<int> > >()) << std::endl;
std::cout << func(std::vector<int>()) << std::endl;
std::cout << func(int()) << std::endl;
std::cout << func(std::vector<std::vector<std::vector<std::vector<std::vector<std::vector<int> > > > > >()) << std::endl;
return 0;
}
will output
3
1
0
6
Upvotes: 1
Reputation: 7482
With C++17
you can write a pretty simple solution:
template<typename T >
constexpr int func(){
if constexpr (is_vector<typename T::value_type>::value )
return 1+func<typename T::value_type>();
return 1;
}
int main() {
cout<< func<vector<vector<vector<vector<vector<int>>>>>>() <<endl;
return 0;
}
which return 5
as expected.
You need to define is_vector
as follows:
template<class T>
struct is_vector{
static bool const value = false;
};
template<class T>
struct is_vector<std::vector<T> > {
static bool const value = true;
};
Upvotes: 2
Reputation: 6240
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
Upvotes: 3
Reputation: 12342
A simple template should solve this. From memory:
template <T> singleFunction(vector<T> &t) {
return t.size();
}
Upvotes: 1