I'm working on heterogenous list that uses std::variant. Is there a way to initialize it every time with a custom set of types for std::variant?

Viewed 51

...or to quickly change types inside std::variant in source code.

Below is the code inside header files for the list itself and its container-element.

// HVector.hh
class HVector: public std::vector<HVElem>
{
public:
    HVector();
    void push(std::variant<Party, Loot> newData);
    void show();
};

//HVElem.hh
class HVElem
{
public:
    HVElem( std::variant<Party, Loot> newData );
    ~HVElem();
    std::variant<Party, Loot> getData();
private:
    std::variant<Party, Loot> data;
};

I'm worried that when I have to change the set of types that HVector can take I'll have manually go through a lot of code changing contents inside "<>" of each std::variant.

  1. Is this just a bad idea of using std::variant in this case?
  2. If yes, should I use templates or std::any?
  3. Is there a way to store types and pass them into HVector during initialization?
  4. Are refactoring tools a solution to the problem?
1 Answers
  1. Is this just a bad idea of using std::variant in this case?

There is too little context, so I have to assume that you are using std::variant because std::variant is what you need.

  1. If yes, should I use templates or std::any?

std::any is for something very different. std::variant is for a limited set of types, std::any is for any type. Pick one or the other depending on what you actully need, not based on easier refactoring or the like.

  1. Is there a way to store types and pass them into HVector during initialization?

You can use an alias:

using my_variant = std::variant<Party,Loot>;

If you like you can make the classes templates and provide the variant type as parameter:

template <typename T>
class HVector: 
{
public:
    HVector();
    void push(T newData);
    void show();
};

this will be more flexible but isn't really necessary.

  1. Are refactoring tools a solution to the problem?

Once you have the alias my_variant and you use that consistently throughout your code, you only have to change it in one single place.

PS: Publicly inheriting from standard containers is often not a good idea. It can be done right, but you have to be careful. I allowed myself to simply ignore that part in above example, because it is only remotely related to the question.

PPS: The situation with std::variant is a bit similar to std::pair. What I mean is that genericity comes at the price of not meaningful names. Even if you use that variant in only one single place in your code, you should give it a meaningful name. When reading your code, I don't understand what a std::variant<Party,Loot> really is. Would be different with an alias that tells me something about the meaning. I didn't know what is a good name. my_variant certainly isn't one.

Related