I am working on a program that needs to be able to create vectors with different dimensions at runtime. I know that C templates are a compile time feature, and I am not sure how to work around this currently. I have seen some examples that use if statements to control the allocation of memory like so:
if (some_condition == 1) {
std::vector<int> x;
} else if (some_condition == 2) {
std::vector<std::vector<int>> x;
} // repeat for how ever many times
This works fine as a temporary solution, but I would really like there to be a way to control the dimension of a created vector without brute forcing if else statements up to some arbitrary number. If it is not possible would it be possible to make my own vector class, but with fixed types? I have tried making a 1 dimensional vector and using math to index it like a multi dimensional vector, but this seems to get complicated fast.
template<typename class_name>
class rvector
{
std::vector<class_name> items;
int depth;
// Some collection type that lays out the format of all the items
}
CodePudding user response:
This is a way to implement the recursive template application:
#include <iostream>
#include <vector>
#include <type_traits>
template<typename T>
struct ID {};
template<size_t i, typename U>
auto n_dim_vec_gen(U u)
{
if constexpr (i) {
return n_dim_vec_gen<i - 1>(std::vector<U>());
} else {
return u;
}
}
template<typename T, size_t i>
using n_dim_vec = decltype(n_dim_vec_gen<i>(std::declval<T>()));
static_assert(std::is_same<n_dim_vec<int, 1>, std::vector<int>>::value);
static_assert(std::is_same<n_dim_vec<int, 2>, std::vector<std::vector<int>>>::value);
If you'd also like to standardize the some_condition
processing, then you need to make a runtime - to - compile-time bridge (a simple switch statement works) and then apply the lambda. You might generate the branches of the switch using e.g. BOOST_PP_FOREACH
, but that might be a little overkill. Then apply the pre-defined lambda.
auto whatToDo = [&](auto x, auto depth) {
// note that depth's type is compile-time
// integral_constant, so you can use it in e.g.
// if constexpr and template arguments
n_dim_vec<int, depth> x;
// ...
};
// this is the runtime - to - compile-time bridge
switch (some_condition) {
#define CASE(I) case I: whatToDo(std::integral_constant<int, I>()); break;
CASE(1)
CASE(2)
CASE(3)
// ...
#undef CASE
};