Search code examples
c++templatesstd-variant

is there a way to use std::variant with arbitrarily many defined types?


I am just learning to use std::variant and I would like to declare a type list consisting of (in principle) arbitrarily many of my user defined types. I.e., something like

template<typename T>
struct MyType{
    T x;
};

template<typename T, int N>
MyClass{
public:
    MyType<T> y;
    int z = N;
    double w;
    MyClass(double b){
        w = b;
    }
};

template<typename T>
using my_type_list = std::variant<
    MyClass<T,1>, MyClass<T,289>, MyClass<T,13>, ...., MyClass<T,5001>
>;

template<typename T>
std::vector<my_type_list> my_big_list = {
    MyClass<T,1> { 2.0 },
    MyClass<T,1> { 3.0 },
    MyClass<T,289> { 9.4 },
    MyClass<T, 13> { 1.3 },
    MyClass<T, 5001> {2.5},
    MyClass<T, 5001> {3.2},
    ..... etc....
};

but where the integer N can in principle be anything.

is there any way that this is possible?


Solution

  • You indicated that you're looking to use another template parameter, to specify the number of values in the variant. In that case, it's a simple matter to use it to construct a std::integer_sequence, and then use it to create your variant type list.

    #include <variant>
    #include <type_traits>
    #include <utility>
    
    template<typename T>
    struct MyType{
        T x;
    };
    
    template<typename T, int N>
    class MyClass{
        MyType<T> y;
        int z = N;
    };
    
    template<typename T, typename sequence> struct my_type_helper;
    
    template<typename T, int ...N>
    struct my_type_helper<T, std::integer_sequence<int, N...>> {
    
        typedef std::variant<MyClass<T, N>...> variant_t;
    };
    
    template<typename T, int N>
    using my_type=
        typename my_type_helper<T, std::make_integer_sequence<int, N>>::variant_t;
    
    static_assert(std::is_same_v<std::variant<MyClass<int, 0>,
              MyClass<int, 1>,
              MyClass<int, 2>>,
    
              my_type<int, 3>>);
    

    The static_assert proves that my_type<int, 3> is equivalent to std::variant<MyClass<int, 0>, MyClass<int, 1>, MyClass<int, 2>>.

    P.S. The int z = N; should likely be constexpr int z=N;.