I have a template class that takes std::variant
as a template parameter:
template<class T>
class X
{
};
X<std::variant<int, float>> x;
I want to add a constraint for T
to be derived from std::variant
.
Then I want to extract template parameters of this variant to use them inside the class.
Like this:
template<class T, std::enable_if_t<
std::is_base_of_v<std::variant<T::_Types>, T>, // _Types = int, float
bool> = true>
class X
{
std::tuple<T::_Types> t; // std::tuple<int, float>
};
X<std::variant<int, float>> x;
The problem is that I cannot get these int, float
parameters from the variant
type.
Is there a way to do this in C++17?
This variant comes from return type of a function.
Because of this I cannot change it for something like variant parameters instead (to take int, float
directly).
The types_list
type traits provides a specialized tuple for the different types that constitute the specialization of the template class T
, otherwise provides an empty tuple. For simplicity, it is used the standard std::tuple
.
To implement the technique, it is sufficient to add a partial specialization that accepts a generic class and its list of template arguments.
Example:
template <typename>
struct types_list
{ using type = std::tuple<>; };
template <template <typename...> typename T, typename ...Args>
struct types_list<T<Args...>>
{ using type = std::tuple<Args...>; };
template <typename T>
using types_list_t = typename types_list<T>::type;
On the other hand, the is_variant
type trait verifies whether the type T
is a specialization of std::variant
.
To implement the condition, it is sufficient to add a partial specialization that accepts a std::variant
specialization.
Example:
template <typename>
struct is_variant
: std::false_type {};
template <typename ...Args>
struct is_variant<std::variant<Args...>>
: std::true_type {};
template <typename T>
inline constexpr bool is_variant_v = is_variant<T>::value;
Thus, the class can be re-implemented in the following way.
template <typename T, typename = std::enable_if_t<is_variant_v<T>>>
class X
{
types_list_t<T> t;
};