I'm working with several different variant implementations and I need to be able to convert between them. Specifically, std::variant, _variant_t, and a few others. I'm trying to create a list of types to use as both a way to instantiate std::variants and as a means to iterate through a list of types in a function to check if the std::variant holds a value of that particular type. My initial thought was something like this.
template <typename ...Args>
struct type_list{
}
I would like to use this as such, then use variadic recursion in a function to test and return the appropriate _variant_t. I won't have a problem with the function implementations if I could just find a way to extract the types from the type list.
using unsigned_types = typelist<uint8_t, uint16_t, uint32_t>;
using unsigned_variant = std::variant<unsigned_types::types>;
template <typename T, typename ...Args>
_variant_t to_variant_t(unsigned_variant& var) {
// auto val = std::get_if<T>(&var);
}
template<typename ...Args>
_variant_t to_variant_t(unsigned_variant& var) {
// Iterate over Args types to check if variant contains type
}
// Example syntax
int main() {
auto std_var = unsigned_variant((uint8_t)42);
auto _var = to_variant_t<unsigned_types::types>();
}
Here is the brute force way I could do this, but I feel it could be more elegant and less repetitive using templates, hence the above constructs.
_variant_t to_variant_t(const unsigned_variant& variant) {
auto uint8_ptr = std::get_if<uint8_t>(&variant);
if (uint8_ptr != nullptr)
return _variant_t((unsigned char)*uint8_ptr);
auto uint16_ptr = std::get_if<uint16_t>(&variant);
if (uint16_ptr != nullptr)
return _variant_t((unsigned short)*uint16_ptr);
// And so on for each unsigned integer type
}
How do I go about storing and extracting the types from type_list? I've tried the following...
template <typename ...Args>
struct type_list{
using types = Args...; // Parameter pack cannot be expanded in this context.
}
But obviously it doesn't compile. I'm missing something here. Any ideas?
CodePudding user response:
You can write a meta function like
template <typename... Types>
auto variant_from_type_list(type_list<Types...>) -> std::variant<Types...>;
and combined with an helper alias of
template <typename TypeList>
using variant_from_type_list_t = decltype(variant_from_type_list(std::declval<TypeList>()));
lets you do
using unsigned_variant = variant_from_type_list_t<unsigned_types>;
CodePudding user response:
You might have your transformation directly in your type_list
:
template <typename ...Args>
struct type_list{
template <template <typename...> class C>
using transform_into = C<Args...>;
};
And then
using unsigned_types = type_list<uint8_t, uint16_t, uint32_t>;
using unsigned_variant = unsigned_types::transform_into<std::variant>;
CodePudding user response:
Parameter packs cannot be stored directly, unfortunately.
Extraction is usually done using partial specialization.
#include <stdint.h>
#include <variant>
template <typename... Args> struct type_list {};
template <template <typename...> class var_impl, typename tlist>
struct make_var {};
template <template <typename...> class var_impl, typename... Args>
struct make_var<var_impl, type_list<Args...>> {
using type = var_impl<Args...>;
};
template <template <typename...> class var_impl, typename tlist>
using make_var_t = typename make_var<var_impl, tlist>::type;
template <typename tlist>
using make_std_var_t = typename make_var<std::variant, tlist>::type;
using unsigned_types = type_list<uint8_t, uint16_t, uint32_t>;
using unsigned_variant = make_std_var_t<unsigned_types>;
static_assert(std::is_same_v<unsigned_variant,
std::variant<uint8_t, uint16_t, uint32_t>>);
CodePudding user response:
Use class template partial specializationto extract types of typelist
#include <variant>
#include <cstdint>
template <typename... Args>
struct typelist{};
template <typename TypeList, template <typename...> typename Template>
struct transform_to;
template <
template <typename...> typename TypeList,
typename... Args,
template <typename...> typename Template>
struct transform_to<TypeList<Args...>, Template> {
using type = Template<Args...>;
};
using unsigned_types = typelist<uint8_t, uint16_t, uint32_t>;
using unsigned_variant = transform_to<unsigned_types, std::variant>::type;
static_assert(
std::is_same_v<unsigned_variant, std::variant<uint8_t, uint16_t, uint32_t>>);