std::variant 和 boost::variant 有什么区别?
What are the differences between std::variant and boost::variant?
在 answer 这个 SO 问题中:
What is the equivalent of boost::variant in the C++ standard library?
有人提到 boost::variant
和 std::variant
有点不同。
- 对于使用这些 类 的人来说,有什么区别?
- 有这些差异,委员会表达采纳
std::variant
的动机是什么?
- 使用其中任何一种编码时,我应该注意什么,以保持与切换到另一种的最大兼容性?
(动机是在 C++17 之前的代码中使用 boost::variant
)
似乎关于变体设计的主要争论点 class 是当对变体的赋值(完成后应销毁旧值)抛出异常时应该发生什么:
variant<std::string, MyClassWithThrowingDefaultCtor> v = "ABC";
v = MyClassWithThrowingDefaultCtor();
选项似乎是:
- 通过将可能的可表示类型限制为不可抛出移动构造的类型来防止这种情况。
- 保留旧值 - 但这需要双缓冲区。
- 在堆上构造新值,将指向它的指针存储在变体中(因此变体本身即使在异常时也不会乱码)。显然,这就是
boost::variant
所做的。
- 有一个 'disengaged' 状态,每个变体都没有值,并在出现此类故障时转到该状态。
- 未定义的行为
- 在类似情况发生后尝试读取其值时使变体抛出异常
如果我没记错的话,后者是被接受的。
这是 Axel Naumann 于 2015 年 11 月在 ISO C++ 博客 post 中总结的内容。
Assignment/emplacement 行为:
boost::variant
可能 allocate memory when performing assignment into a live variant
. There are a number of rules that govern when this can happen,因此 boost::variant
是否分配内存取决于它实例化的 Ts
。
std::variant
永远不会 动态分配内存。但是,作为对C++对象复杂规则的让步,如果一个assignment/emplacement抛出,那么variant
可能进入"valueless_by_exception"状态。在此状态下,无法访问 variant
,也无法访问任何其他用于访问特定成员的函数。
只有assignment/emplacement抛出才能进入该状态
Boost.Variant 包括 recursive_variant
,其中 allows a variant
to contain itself。它们本质上是围绕指向 boost::variant
的指针的特殊包装器,但它们与访问机制相关联。
std::variant
没有这样的助手类型。
std::variant
提供对 post-C++11 功能的更多使用。例如:
转发其构成类型的特殊成员函数的noexcept
状态
它具有基于可变模板的就地构造函数和安置函数。
缺陷解决方案 applied to C++17 may mean that it will also forward trivial copyability of its types。也就是说,如果所有类型都是可复制的,那么 variant<Ts>
.
也是如此
std::variant 与 boost::variant
略有不同
- std::variant 在头文件中而不是在
中声明
- std::variant 从不分配内存
- std::variant 可与 constexpr
一起使用
- 不用写boost::get(&variable),你必须写std::get_if(&variable) for std::variant
- std::variant 无法递归保持自身并错过了其他一些高级技术
- std::variant 可以就地构建对象
- std::variant 有 index() 而不是 which()
在 answer 这个 SO 问题中:
What is the equivalent of boost::variant in the C++ standard library?
有人提到 boost::variant
和 std::variant
有点不同。
- 对于使用这些 类 的人来说,有什么区别?
- 有这些差异,委员会表达采纳
std::variant
的动机是什么? - 使用其中任何一种编码时,我应该注意什么,以保持与切换到另一种的最大兼容性?
(动机是在 C++17 之前的代码中使用 boost::variant
)
似乎关于变体设计的主要争论点 class 是当对变体的赋值(完成后应销毁旧值)抛出异常时应该发生什么:
variant<std::string, MyClassWithThrowingDefaultCtor> v = "ABC";
v = MyClassWithThrowingDefaultCtor();
选项似乎是:
- 通过将可能的可表示类型限制为不可抛出移动构造的类型来防止这种情况。
- 保留旧值 - 但这需要双缓冲区。
- 在堆上构造新值,将指向它的指针存储在变体中(因此变体本身即使在异常时也不会乱码)。显然,这就是
boost::variant
所做的。 - 有一个 'disengaged' 状态,每个变体都没有值,并在出现此类故障时转到该状态。
- 未定义的行为
- 在类似情况发生后尝试读取其值时使变体抛出异常
如果我没记错的话,后者是被接受的。
这是 Axel Naumann 于 2015 年 11 月在 ISO C++ 博客 post 中总结的内容。
Assignment/emplacement 行为:
boost::variant
可能 allocate memory when performing assignment into a livevariant
. There are a number of rules that govern when this can happen,因此boost::variant
是否分配内存取决于它实例化的Ts
。std::variant
永远不会 动态分配内存。但是,作为对C++对象复杂规则的让步,如果一个assignment/emplacement抛出,那么variant
可能进入"valueless_by_exception"状态。在此状态下,无法访问variant
,也无法访问任何其他用于访问特定成员的函数。只有assignment/emplacement抛出才能进入该状态
Boost.Variant 包括
recursive_variant
,其中 allows avariant
to contain itself。它们本质上是围绕指向boost::variant
的指针的特殊包装器,但它们与访问机制相关联。std::variant
没有这样的助手类型。std::variant
提供对 post-C++11 功能的更多使用。例如:转发其构成类型的特殊成员函数的
noexcept
状态它具有基于可变模板的就地构造函数和安置函数。
缺陷解决方案 applied to C++17 may mean that it will also forward trivial copyability of its types。也就是说,如果所有类型都是可复制的,那么
variant<Ts>
. 也是如此
std::variant 与 boost::variant
略有不同- std::variant 在头文件中而不是在
- std::variant 从不分配内存
- std::variant 可与 constexpr 一起使用
- 不用写boost::get(&variable),你必须写std::get_if(&variable) for std::variant
- std::variant 无法递归保持自身并错过了其他一些高级技术
- std::variant 可以就地构建对象
- std::variant 有 index() 而不是 which()