Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hiding template arguments in std::variant

Tags:

c++

c++17

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.

like image 964
Savino Avatar asked Jan 22 '26 04:01

Savino


1 Answers

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;
like image 126
Caleth Avatar answered Jan 23 '26 19:01

Caleth



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!