Assume that I have the following class definition:
template <unsigned int N>
class foo
{
boost::tuples::tuple<...> bar;
};
Given the compile-time constant N
, I would like to expand the type of bar
to be a tuple that holds N
elements of a specified type. That is, the type of foo<2>::bar
would be boost::tuples::tuple<T, T>
. I'm guessing that I can use Boost.MPL for this, but I haven't figured out the exact sequence yet. I think I could do:
template <typename T, int N>
struct type_repeater
{
typedef typename boost::mpl::fold<
boost::mpl::range_c<T, 0, N>,
boost::mpl::vector<>,
boost::mpl::push_back<_1, T>
>::type type;
};
So then for instance type_repeater<T, 2>::type
would be equivalent to boost::mpl::vector<T, T>
. I'm just not sure how/if I can take that type list and inject it into the argument list of a tuple, like I want. Is this possible?
This seems to be a good minimal example using C++11
#include <tuple>
template <unsigned int N, typename T>
struct type_repeater {
typedef decltype(std::tuple_cat(std::tuple<T>(), typename type_repeater<N-1, T>::type())) type;
};
template <typename T>
struct type_repeater<0, T> {
typedef decltype(std::tuple<>()) type;
};
int main() {
type_repeater<3, float>::type asdf;
std::get<0>(asdf);
std::get<1>(asdf);
std::get<2>(asdf);
}
Although this is totally doable with variadic templates and std::tuple
, the best solution for what you want I think is to just use std::array
. If you simply want a container with N instances of T, the std::array
signature is already template <typename T, std::size_t N> class array
. I think it fits your need exactly.
Having said that, if you really want std::tuple
for some reason you can do it like so:
#include <tuple>
/* Forward declaration. */
template <std::size_t N, typename T>
class Tuple;
/* Convenience type alias. */
template <std::size_t N, typename T>
using TTuple = typename Tuple<N, T>::type;
/* Base case. */
template <typename T>
class Tuple<0, T> {
public:
using type = std::tuple<>;
}; // Tuple<0>
/* Recursive case. */
template <std::size_t N, typename T>
class Tuple {
public:
/* Note the use of std::declval<> here. */
using type = decltype(std::tuple_cat(std::declval<std::tuple<T>>(),
std::declval<TTuple<N - 1, T>>()));
}; // Tuple<N, T>
/* std::declval<> is necessary to support non default constructable classes. */
class NoDefault {
public:
NoDefault() = delete;
}; // Foo
/* Sample use. */
static_assert(std::is_same<TTuple<2, NoDefault>,
std::tuple<NoDefault, NoDefault>>::value, "");
int main() {}
Note: If you don't have access to C++11 but do have access to boost, boost::array
and boost::tuples::tuple
will do fine in lieu of std::array
and std::tuple
.
Since you explicitly ask for a way to make mpl::vector into a runtime container, I recommend you stay Boosty and use Fusion's as_vector:
Given your initial example where you mol::fold to get an mpl::vector, you would then use:
boost::fusion::result_of::as_vector<
mpl::vector<T, T>
>::type;
To get a Fusion Vector, which seems to be what you want. Boost Fusion fills the gap between the compile-time and runtime world.
Also, this is pre C++11, which is still important in many (maybe most?) projects.
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