英文:
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<int, std::vector<List>> {
public:
using base = std::variant<int, std::vector<List>>;
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<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.
答案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 << x << '\n'; }
void operator()(const std::vector<List>& l) const {
for(auto& v : l) std::visit(*this, v);
}
};
(The recursive visitor will be possible to simplify in C++23 with deducing this
)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论