I have a variadic template typelist:
template <class... Types>
struct typelist {};
Then how can I pass it to some external code that expects a parameter pack, say std::tuple
. In other word, I need to store the parameter pack as a member or typedef in my typelist, like
...
struct typelist {
using types = Types; // Imaginary syntax
}
Yet this is rejected by the compiler saying Types is unexpanded.
Any workaround?
This question is mentioned in another way in comments of this question, yet was not covered by the existing answer.
Details as requested in comments:
If I compile (-std=c++17):
template <class... T>
struct typelist {};
std::tuple<typelist<int, int>> tp{0,1};
g++ gives error: no matching function for call to ‘std::tuple<typelist<int, int> >::tuple(<brace-enclosed initializer list>)’
std::tuple<typelist<int, int>> tp{0,1};
If I compile (-std=c++17):
template <class... T>
struct typelist {
using types = T;
};
g++
gives error: parameter packs not expanded with ‘...’:
using types = T;
You need a bit of boilerplate to get the right tuple
specialization out of a typelist
, for you can't simply store the parameter pack as it is.
As an example, you could do that by using properly a function declaration and an using declaration:
#include<tuple>
#include<utility>
#include<type_traits>
template <class... T>
struct typelist {};
template<typename... T>
std::tuple<T...> foo(typelist<T...>);
template<typename L>
using tupleFromTypelist = decltype(foo(std::declval<L>()));
int main() {
using tl = typelist<int, int>;
tupleFromTypelist<tl> tp{0,1};
static_assert(std::is_same<tupleFromTypelist<tl>, std::tuple<int, int>>::value, "!");
}
Or an helper class like the one in the following example:
#include<tuple>
#include<utility>
#include<type_traits>
template <class... T>
struct typelist {};
template<typename>
struct helper;
template<typename... T>
struct helper<typelist<T...>> {
using type = std::tuple<T...>;
};
int main() {
using tl = typelist<int, int>;
helper<tl>::type tp{0,1};
static_assert(std::is_same<helper<tl>::type, std::tuple<int, int>>::value, "!");
}
Otherwise, let typelist
expose the tuple
specialization and get it directly from it:
#include<tuple>
#include<utility>
#include<type_traits>
template <class... T>
struct typelist {
using tuple = std::tuple<T...>;
};
int main() {
using tl = typelist<int, int>;
tl::tuple tp{0,1};
static_assert(std::is_same<tl::tuple, std::tuple<int, int>>::value, "!");
}
If it's the only type for which you want to use the parameter pack, this is the easiest approach.
You can't store a parameter pack in a type alias. You need to use template argument deduction to extract the arguments of your type_list
for reuse. One way is to use a dummy function like so:
template <typename... Args>
struct type_list {};
template <typename... Args>
std::tuple<Args...> to_tuple(type_list<Args...>);
template <typename TypeList>
struct type_list_to_tuple {
using type = decltype(to_tuple(std::declval<TypeList>()));
};
template <typename TypeList>
using type_list_to_tuple_t = typename type_list_to_tuple<TypeList>::type;
int main() {
using my_type_list = type_list<int, float>;
using my_tuple = type_list_to_tuple_t<my_type_list>;
static_assert(std::is_same_v<my_tuple, std::tuple<int, float>>);
}
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