Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
658 views
in Technique[技术] by (71.8m points)

templates - Can I extend variant in C++?

I'm not sure that this is possible, but say I have:

using my_variant = std::variant<Class1, Class2, Class3>;

Now at some point, I create a Class4 and would like to extend my_variant2 to include all of my_variant along with Class4 (in a general way, i.e. not just using another using...) so that I can do something like create an array std::array<my_variant2, n>.

Is this something that can be done?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

There are two steps to achieving this. The first is to identify the list of types used in the original std::variant and the second is to construct a new std::variant type with the original arguments plus the one to add.

Partial template specialization can be used to write a trait that will obtain the list of template types used in a given std::variant :

#include <variant>

template<class T>
struct t_variant_cat;

template<class ... Old>
struct t_variant_cat<std::variant<Old...>> {
    // Old is a parameter pack containing all of 
    //  template arguments of the std::variant
};

Next we add another template argument that specifies the type to add and define an alias for this new type.

#include <variant>

template<class T, class New>
struct t_variant_cat;

template<class ... Old, class New>
struct t_variant_cat<std::variant<Old...>, New> {
    using type = std::variant<Old..., New>;
};

typename t_variant_cat<my_variant, Class4>::type should now yield std::variant<Class1, Class2, Class3, Class4>. For convenience we can add a type alias to avoid having to write typename and ::type each time :

template<class Old, class New>
using t_variant_cat_t = typename t_variant_cat<Old, New>::type;

The usage would be :

#include <variant>

template<class T, class New>
struct t_variant_cat;

template<class ... Old, class New>
struct t_variant_cat<std::variant<Old...>, New> {
    using type = std::variant<Old..., New>;
};

template<class Old, class New>
using t_variant_cat_t = typename t_variant_cat<Old, New>::type;

using old = std::variant<int, float>;
using extended = t_variant_cat_t<old, double>;

// Makes sure this actually works
static_assert(std::is_same_v<extended, std::variant<int, float, double>>,
    "Something is wrong.");

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...