C++ std::variant与std::any的区别

59
C++17引入了std::variantstd::any,它们都能在一个对象下存储不同类型的值。对我来说,它们有些相似(它们是吗?)。
此外,std::variant限制了除这个之外的输入类型。为什么我们应该优先选择使用更简单的std::any而不是std::variant呢?

std::variant 只能使用预定义的一组类型,而 std::any 则可以与 任何类型 一起使用。哪个更好取决于您的用例。 - πάντα ῥεῖ
@πάνταῥεῖ:什么是“预定义类型集”? - masoud
7
大致上来说,第一个是编译时,第二个是运行时。 - Evg
2
没有std::anystd::visit(),在可能的情况下,这应该是更喜欢std::variant的一个有效理由,以我个人看来。 - max66
8
在我看来,这就像是 void* 和 union 之间的比较。 - Ayxan Haqverdili
显示剩余2条评论
3个回答

105

检查越多的问题在编译时检查,运行时错误就越少。

variant 保证它包含列表中的一种类型 (加上值为空的异常)。 它提供了一种方法,让您保证操作它的代码使用 std::visit 考虑 variant 中的每个 case,甚至是对于 pairvariant(或更多) 的每个 case。

any 不会这样做。 使用 any 最好的办法是“如果类型不完全符合我要求,则某些代码将无法运行”。

variant 存在于自动存储中。 any 可能使用自由存储区; 这意味着 any 具有性能和 noexcept(false) 问题,而 variant 则没有。

对于包含 N 种类型的 any,检查它是 O(N) -- 对于 variant 来说是 O(1)。

any 是一个装扮起来的 void*variant 是一个装扮起来的 union

any 无法存储非可复制或非可移动类型。 variant 可以。

variant 的类型是代码读者的文档。

通过 API 传递 variant<Msg1,Msg2,Msg3> 使操作变得明显;通过传递 any 则意味着理解 API 需要可靠的文档或阅读实现源代码。

任何被静态类型语言所困扰的人都会理解使用 any 的风险。
这并不意味着 any 是不好的;它只是不能像 variant 一样解决问题。作为可复制的对象,用于类型擦除的目的,它可能非常有用。运行时动态类型有其存在的意义,但这个存在的意义并非“无处不在”,而是“在你无法避免它的地方”。

11
一个简洁明了的解释是:“any 类型就像是一个经过装饰的 void* 指针,variant 类型就像是一个经过装饰的 union 联合体”。 - TonySalimi

10
区别在于对象存储在由std::variant分配的内存中: cppreference.com - std::variant 与联合类似,如果变体保存某个对象类型T的值,则T的对象表示直接分配在变体本身的对象表示中。变体不允许分配额外(动态)内存。而对于std::any则不可能实现这一点。
因此,std::variant仅需要一个内存分配来存储std::variant本身,并且它可以保留在堆栈上。

5
除了永远不使用额外的堆内存之外,variant 还有一个优点:您可以使用 std::visit 访问 variant,但不能访问 any

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接