is it possible in modern c to write a function that given a number n and a type return a n-dimensional vector type.
1,float -> return std::vector<float>
2,float -> return std::vector<std::vector<float>>
and so on.
CodePudding user response:
Here is a compile time approach using template specialization. We apply std::vector<>
recursively until we reach the specialization for N == 0
, where the final type
is set to T
:
#include <type_traits>
#include <vector>
template<std::size_t N, typename T>
struct recursive_vector {
using type = std::vector<typename recursive_vector<N - 1, T>::type>;
};
template<typename T>
struct recursive_vector<0, T> {
using type = T;
};
template<std::size_t N, typename T>
using vec = recursive_vector<N, T>::type;
so vec<3, float>
becomes vector<vector<vector<float>>>
:
int main() {
vec<3, float> v;
using std::vector;
static_assert(std::is_same_v<decltype(v), vector<vector<vector<float>>>>);
}
CodePudding user response:
Is it possible in modern C to write a function that given a number
n
and a type return an-dimensional vector
type?
Compile time
If n
is known at compile time, the job easy, which is already given in the other answer. Alternatively, you could also do:
#include <vector>
template<typename T, std::size_t N>
struct vec : public vec<std::vector<T>, N - 1u> {};
template<typename T> struct vec<T, 0u> { using type = T; };
template<typename T, std::size_t N> using vec_t = typename vec<T, N>::type;
Now vec_t<float, 5u>
means std::vector<std::vector<std::vector<std::vector<std::vector<float>>>>>
(See a live demo in godbolt.org)
Run time
When n
is run time depended, one possible solution is to wrap the possible multidimensional vectors types to std::variant
(Since c 17).
Following is an example code.
#include <vector>
#include <variant> // std::variant
// type aliases for the multi-dim vectors
template<typename T> using Vec1D = std::vector<T>;
template<typename T> using Vec2D = Vec1D<Vec1D<T>>;
template<typename T> using Vec3D = Vec1D<Vec2D<T>>;
// ... so on (hope that you wouldn't need more than 4 or 5!)
template<typename T>
using VecVariants = std::variant<Vec1D<T>, Vec2D<T>, Vec3D<T>/*, so on ...*/>;
template<typename T> auto getVector_of(const std::size_t n)
{
if (n == 1) return VecVariants<T>{Vec1D<T>{}};
if (n == 2) return VecVariants<T>{Vec2D<T>{}};
if (n == 3) return VecVariants<T>{Vec3D<T>{}};
// ... so on
return VecVariants<T>{Vec3D<T>{}}; // some default return!
}
template<typename T> void doSomething(const VecVariants<T>& vec)
{
std::visit([](auto&& arg) {
using Type = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<Type, Vec1D<T>>)
std::cout << "... do something with Vec1D\n";
else if constexpr (std::is_same_v<Type, Vec2D<T>>)
std::cout << "... do something with Vec2D\n";
else if constexpr (std::is_same_v<Type, Vec3D<T>>)
std::cout << "... do something with Vec3D\n";
// .... so on
else
std::cout << "... default!\n";
}, vec);
}
Now you can pass run time n
int main()
{
std::size_t n{ 5 };
while (n)
doSomething(getVector_of<float>(n--)); // n must be 0u < n <= MAX_n you defined!
}