I have a set of template classes that I want to put inside a std::variant. The following works, but is rather ugly (I have many more classes in the variant, with many template parameters).
template <typename T>
struct Type1
{ };
template <typename B, typename C>
struct Type2
{ };
template <typename A, typename B, typename C>
using Variant = std::variant<Type1<A>, Type2<B,C>>;
Is it possible to "hide" the template arguments in a similar way to this? (doesn't compile)
template <typename A>
using Type1T = Type1<A>
template <typename B, typename C>
using Type2T = Type2<B, C>
using Variant = std::variant<Type1T, Type2T>
error: type/value mismatch at argument 1 in template parameter list for 'template class std::variant'
Adding typename also doesn't seem to work.
You can't use std::variant to do that. You can use std::any, but you can't visit an any.
The problem is that Type1 and Type2 are not types, they are type templates. There is an infinity of instantiations of Type1, which are all unrelated types as far as a visit is concerned.
I suggest you make non-template Type1Base which you derive Type1<T> from, and have a std::variant<std::unique_ptr<Type1Base>, std::unique_ptr<Type2Base>, ...>
Edit - even template_variant is not possible, there is no way to recover which instantiation of the selected template is the active member. If that were possible, you have the complication that every visitor has to have an overload for every instantiation of every template.
Original attempt:
You could write your own template variant, which would have a mix of members similar to std::any and std::variant
template<template<class...> class ... Templates>
class template_variant
{
std::any value;
public:
// constructors, operator=, etc
// Observers
constexpr std::size_t index() const noexcept; // Which template this contains
const std::type_info& type() const noexcept; // returns the typeid of the contained value
// Modifiers
template <template<typename...> class T, class... Args>
T<Args...>&
emplace(Args&&... args)
{
value.emplace<T<Args...>>(std::forward<Args>(args)...);
}
template <size_t I, class... Args>
template_variant_alternative_t<I, variant, Args...>&
emplace(Args&&... args)
{
value.emplace<template_variant_alternative_t<I, variant, Args...>>(std::forward<Args>(args)...);
}
void swap( template_variant& rhs ) noexcept;
// Non-member functions
friend template <std::size_t I, template<class...> class ... Templates, class... Args>
constexpr template_variant_alternative_t<I, template_variant<Templates...>, Args...>&
std::get(template_variant<Templates...>& v)
{
try
{
return std::any_cast<template_variant_alternative_t<I, template_variant<Templates...>, Args...>&>(v.value);
}
catch (std::bad_any_cast & e)
{
throw bad_template_variant_access(e);
}
}
// and &&, and const&, and const&&
template <template<class...> class T, template<class...> class ... Templates, class... Args>
constexpr T<Args...>&
std::get(template_variant<Templates...>& v)
{
try
{
return std::any_cast<T<Args...>&>(v.value);
}
catch (std::bad_any_cast & e)
{
throw bad_template_variant_access(e);
}
}
// and &&, and const&, and const&&
// etc.
};
template <std::size_t I, typename Variant, class... Args>
struct template_variant_alternative;
template <std::size_t I, template<class...> class ... Templates, class... Args>
struct template_variant_alternative<I, template_variant<Templates...>, Args...>
{
using type = // apply Args... to Ith template in Templates
};
template <std::size_t I, typename Variant, class... Args>
using template_variant_alternative_t = template_variant_alternative<I, Variant, Args...>::type;
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