I need to interface with code that uses (misuses) tuples on the form:
using Tuple = std::tuple<double, double, double, double, int, int, int, int>; // etc..
I wonder if there is a way to define this tuples with templates instead in the form:
using Tuple = SomeType<4, double, 4, int>::Type; // expands to the above tuple
And specify the number of arguments instead of specify each type.
I would prefer to only use std libs, but boost is accepted. And I need it to work with c++14. It is easy to do with macros, but I already have a macro solution, and I do not like having macros in the code for this kind of code.
The tuple above is a small example. In reality the tuples is much larger, contains many more types and more of each type.
I am not aware of some std
facility that does what you want directly.
The tricky part is to have a variadic template with mixed non-type and type parameters. The issue can be avoided by using a helper:
template <typename T,size_t reps>
struct repeated_type {
using type = T;
static const size_t N = reps;
};
Usage can look like this:
int main() {
using two_ints = repeated_type<int,2>;
using three_doubles = repeated_type<double,3>;
using my_tuple = n_tuple<two_ints,three_doubles>;
static_assert(std::is_same<
std::tuple<int,int,double,double,double>,
my_tuple
>::value);
}
Using a std::index_sequence
we can get a std::tuple<T,T,T,...T>
via std::make_tuple
template <typename T,std::size_t...n>
auto n_tuple_impl(std::index_sequence<n...>){
return std::make_tuple( (n,T{})...);
}
template <typename repT>
using n_tuple_single = decltype(
n_tuple_impl<typename repT::type>(
std::make_index_sequence<repT::N>()
)
);
Concatenetating several of them can be done via std::tuple_cat
:
template <typename...repT>
using n_tuple = decltype(
std::tuple_cat(
( n_tuple_single<repT>() )...
)
);
Live Demo.
In two places I require default construction. If needed this could be circumvented via std::declval
. No instances are actually created.
For the interested reader, here is a rather messy C++11 implementation that is based on recursion instead of std::index_sequence
and fold expressions to achieve the same.
Here is a short solution using Boost.MP11
and can work with any type list holder (e.g. std::tuple
, boost::mp11::mp_list
, etc).
#include <boost/mp11/algorithm.hpp>
#include <cstddef>
#include <tuple>
#include <type_traits>
template<class T, std::size_t N, template<class...> class THolder = std::tuple>
struct repeater {
using type = boost::mp11::mp_repeat_c<THolder<T>, N>;
};
template<class T, std::size_t N>
using repeater_t = typename repeater<T, N>::type;
int main() {
using expected_t = std::tuple<double, double, double, double, int, int, int, int>;
using actual_t = boost::mp11::mp_append<repeater_t<double, 4>, repeater_t<int, 4>>;
static_assert(std::is_same_v<actual_t, expected_t>);
}
Here, we leverage boost::mp11::mp_repeat_c
to build the type holder holding N
types of type T
. The type list we default to is std::tuple
as requested. Then, at the call site, it's just a matter of appending the tuples together via boost::mp11::mp_append
to get down to one tuple.
Wandbox link
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