在这个SO问题的答案中:
提到了boost::variant
和std::variant
有所不同。
- 对于使用这些类的人来说,它们有哪些不同之处?
- 委员会表达了什么动机来采用带有这些差异的
std::variant
? - 在编写任一代码时,我应该注意什么,以保持与切换到另一个代码的最大兼容性?
(动机是在C++17之前的代码中使用boost::variant
)
在这个SO问题的答案中:
提到了boost::variant
和std::variant
有所不同。
std::variant
?(动机是在C++17之前的代码中使用boost::variant
)
赋值/放置行为:
boost::variant
可能会在将值赋给一个已存在的 variant
时分配内存。有很多规则来控制这个行为的发生,因此一个 boost::variant
是否会分配内存取决于它被实例化时的 Ts
。
std::variant
绝不会动态分配内存。然而,作为对 C++ 对象复杂规则的让步,如果赋值/放置操作抛出异常,那么 variant
可能进入“valueless_by_exception”状态。variant
在这种状态下无法访问,也不能使用任何其他访问特定成员的函数。
只有在赋值/放置操作抛出异常时才会进入这种状态。
Boost.Variant 包括 recursive_variant
,它允许一个 variant
包含它自己。它们本质上是指向 boost::variant
的指针的特殊包装器,但它们与访问机制相结合。
std::variant
没有这样的辅助类型。
std::variant
提供了更多使用 C++11 之后特性的方式。例如:
它转发了其组成类型的特殊成员函数的 noexcept
状态。
它具有基于可变参数模板的原地构造函数和放置函数。
缺陷解决方案应用于C++17可能意味着它也会转发其类型的平凡可复制性。也就是说,如果所有类型都是平凡可复制的,则variant<Ts>
也将如此。
std::variant
类的情况下,向 namespace std
添加一些内容,以实现这种递归功能? - einpoklumrecursive_variant
的重点在于它允许 visit
自动解包并访问它所引用的对象。因此,你必须将这个机制构建到 std::visit
中。但是,这不可能在替换std::visit
的情况下完成,而您无法这样做。当然,您可以在自己的命名空间中制作自己的版本的std::visit
以进行解包/访问。 - Nicol Bolasstd::visit
的使用。这样,您就可以编写自己的 variant
,使用该机制并进行自己的递归访问。 - Nicol Bolasstd :: variant
,这可能会改变。@DanNissenbaum:您可以在标准邮件列表中提出此问题(甚至撰写实际提案)。 - einpoklum在设计变体类时,最有争议的主要问题似乎是当对变体进行赋值(完成后应销毁旧值)时抛出异常时应该发生什么:
variant<std::string, MyClassWithThrowingDefaultCtor> v = "ABC";
v = MyClassWithThrowingDefaultCtor();
如果我没错的话,后者已经被接受。
这是摘自Axel Naumann的ISO C ++博客文章(2015年11月)的摘要。
std::variant与boost::variant略有不同
boost::variant
和boost::variant2
是两个不同的库。问题是关于前者的,但值得注意的是,boost::variant2
的官方文档指出它与std::variant
是API兼容的,但有一些附加条件:https://www.boost.org/doc/libs/1_75_0/libs/variant2/doc/html/variant2.html#design_differences_with_stdvariant。另请参阅Boost项目列表:https://www.boost.org/doc/libs/1_75_0/ - Max Barraclough