是否可以继承自std::variant以使其递归?

huangapple go评论76阅读模式
英文:

Is it okay to inherit from an std::variant in order to make it recursive?

问题

这个问题源自去年的一个Reddit帖子,讨论Advent of Code问题

我提到使std::variant递归的唯一方法是将其包装在一个struct中,这样您就可以前向声明该struct,因为没有办法前向声明模板的实例化,例如:
<!-- language:C++ -->
struct wrapped_list;
using list = std::variant<int, std::vector<wrapped_list>>;
struct wrapped_list {
list val;
};

另一位帖子建议使用继承而不是组合:

class List;

class List : public std::variant&lt;int, std::vector&lt;List&gt;&gt; {  
  public:  
    using base = std::variant&lt;int, std::vector&lt;List&gt;&gt;;  
    using base::base;  
    using base::operator=;  
};  

这种方法更好,因为您无需处理仅用于满足声明变量要求的包装struct

然而,我习惯于不从标准库类型继承。上述声明是可移植和合法的C++吗?在这样的变量上调用std::visit是官方未定义行为吗?等等。

英文:

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.
<!-- language:C++ -->
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&lt;int, std::vector&lt;List&gt;&gt; {  
  public:  
    using base = std::variant&lt;int, std::vector&lt;List&gt;&gt;;  
    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.

答案1

得分: 2

是的。

不,对于这样的变体调用std::visit没有官方的未定义行为问题。你可以实现访问者以进行递归调用,例如:

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);
    }
};

演示

(在C++23中,使用推导this将可能简化递归访问者。)

英文:

> 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 &lt;&lt; x &lt;&lt; &#39;\n&#39;; }
    
    void operator()(const std::vector&lt;List&gt;&amp; l) const {
        for(auto&amp; v : l) std::visit(*this, v);
    }
};

Demo

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

huangapple
  • 本文由 发表于 2023年6月8日 02:31:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76426154.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定