boost::variant 和 boost::any 如何工作?
boost 库中的variant 和any 内部如何工作?在我正在进行的一个项目中,我目前使用标记联合。我想使用其他东西,因为 C++ 中的联合不允许您使用带有构造函数、析构函数或重载赋值运算符的对象。
我查询了any和variant的大小,并用它们做了一些实验。在我的平台中,variant 采用其最长可能类型的大小加上 8 个字节:我认为它只是 8 个字节的类型信息,其余的是存储的值。另一方面,any 只占用 8 个字节。因为我在 64 位平台上,所以我猜 any 只是保存一个指针。
Any 如何知道它持有什么类型? Variant 如何通过模板实现其功能?在使用这些类之前我想更多地了解它们。
How do variant and any from the boost library work internally? In a project I am working on, I currently use a tagged union. I want to use something else, because unions in C++ don't let you use objects with constructors, destructors or overloaded assignment operators.
I queried the size of any and variant, and did some experiments with them. In my platform, variant takes the size of its longest possible type plus 8 bytes: I think it my just be 8 bytes o type information and the rest being the stored value. On the other hand, any just takes 8 bytes. Since i'm on a 64-bit platform, I guess any just holds a pointer.
How does Any know what type it holds? How does Variant achieve what it does through templates? I would like to know more about these classes before using them.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您阅读 boost::any 文档,它们会提供该想法的来源: http://www.two-sdg.demon.co.uk/curbralan/papers/ValuedConversions.pdf
这是基本的信息隐藏,是一项必备的 C++ 技能。学起来吧!
由于这里投票最高的答案是完全不正确的,而且我怀疑人们实际上会去查看源代码来验证这一事实,这里有一个类似接口的基本实现,它将用 f() 函数包装任何类型,并且允许调用它:
boost::any 执行相同的基本操作,除了 f() 实际上返回 typeinfo const& 并提供对any_cast 函数进行工作的其他信息访问。
If you read the boost::any documentation they provide the source for the idea: http://www.two-sdg.demon.co.uk/curbralan/papers/ValuedConversions.pdf
It's basic information hiding, an essential C++ skill to have. Learn it!
Since the highest voted answer here is totally incorrect, and I have my doubts that people will actually go look at the source to verify that fact, here's a basic implementation of an any like interface that will wrap any type with an f() function and allow it to be called:
boost::any does the same basic thing except that f() actually returns
typeinfo const&
and provides other information access to the any_cast function to work.boost::any
和boost::variant
之间的主要区别在于any
可以存储任何类型,而variant
> 只能存储一组枚举类型中的一个。any
类型存储一个指向对象的void*
指针,以及一个typeinfo
对象来记住底层类型并强制执行某种程度的类型安全。在 boost::variant 中,它计算最大大小的对象,并使用“placement new”在此缓冲区内分配对象。它还存储类型或类型索引。请注意,如果您安装了 Boost,您应该能够在“any.hpp”和“variant.hpp”中看到源文件。只需在“/usr”、“/usr/local”和“/opt/local”中搜索“include/boost/variant.hpp”和“include/boost/any.hpp”,直到找到已安装的标头,然后你可以看一下。
编辑::holder作为
正如下面的评论所指出的,我对 boost::any 的描述略有不准确。虽然它可以使用
void*
实现(以及模板化销毁回调以正确删除指针),但实际实现使用any::placeholder*
,其中 < code>anyany::placeholder
的子类,用于统一类型。The key difference between
boost::any
andboost::variant
is thatany
can store any type, whilevariant
can store only one of a set of enumerated types. Theany
type stores avoid*
pointer to the object, as well as atypeinfo
object to remember the underlying type and enforce some degree of type safety. Inboost::variant
, it computes the maximum sized object, and uses "placement new" to allocate the object within this buffer. It also stores the type or the type index.Note that if you have Boost installed, you should be able to see the source files in "any.hpp" and "variant.hpp". Just search for "include/boost/variant.hpp" and "include/boost/any.hpp" in "/usr", "/usr/local", and "/opt/local" until you find the installed headers, and you can take a look.
Edit
As has been pointed out in the comments below, there was a slight inaccuracy in my description of boost::any. While it can be implemented using
void*
(and a templated destroy callback to properly delete the pointer), the actualy implementation usesany<T>::placeholder*
, withany<T>::holder<T>
as subclasses ofany<T>::placeholder
for unifying the type.boost::any
只是在模板化构造函数运行时快照typeinfo
:它有一个指向非模板化基类的指针,该基类提供对 typeinfo 的访问,以及派生的构造函数满足该接口的特定类型的类。实际上可以使用相同的技术来捕获一组类型的其他通用功能(例如流、通用运算符、特定函数),尽管 boost 不提供对此的控制。boost::variant 在概念上与您之前所做的类似,但不是字面上使用
union
而是采用手动方法在其缓冲区中放置构造/销毁对象(同时处理对齐问题)显式地)它解决了 C++ 在实际联合中具有复杂类型的限制。boost::any
just snapshots thetypeinfo
while the templated constructor runs: it has a pointer to a non-templated base class that provides access to the typeinfo, and the constructor derived a type-specific class satisfying that interface. The same technique can actually be used to capture other common capabilities of a set of types (e.g. streaming, common operators, specific functions), though boost doesn't offer control of this.boost::variant is conceptually similar to what you've done before, but by not literally using a
union
and instead taking a manual approach to placement construction/destruction of objects in its buffer (while handling alignment issues explicitly) it works around the restrictions that C++ has re complex types in actualunion
s.