2

This question comes out of a reddit thread about an Advent of Code problem from last year.

I had mentioned that the only way to make an std::variant recursive was to wrap it in a struct so you can forward declare the struct as there is no way to forward declare an instantiation of a template, e.g.

struct wrapped_list;
using list = std::variant<int, std::vector<wrapped_list>>;
struct wrapped_list {
    list val;
}; 

Some other poster suggested using inheritance rather than composition:

class List;

class List : public std::variant<int, std::vector<List>> {  
  public:  
    using base = std::variant<int, std::vector<List>>;  
    using base::base;  
    using base::operator=;  
};  

which is better in the sense that you do not have to deal with a wrapper struct that serves no purpose other than satisfying syntax requirements for declaring the variant.

However, I am used to never inheriting from types in the standard library. Is the above declaration portable and legal C++? Is calling std::visit on such a variant officially undefined behavior? etc.

jwezorek
  • 8,592
  • 1
  • 29
  • 46

1 Answers1

2

Is the above declaration portable and legal C++?

Yes.

Is calling std::visit on such a variant officially undefined behavior?

No, there's no problem doing that. You could implement the visitor to call itself recursively for example:

struct visitor {
    void operator()(int x) const { std::cout << x << '\n'; }
    
    void operator()(const std::vector<List>& l) const {
        for(auto& v : l) std::visit(*this, v);
    }
};

Demo

(The recursive visitor will be possible to simplify in C++23 with deducing this)

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108