C++ boost::variant 和 boost::any 如何工作?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4988939/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do boost::variant and boost::any work?
提问by salvador p
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.
来自 boost 库的变体和任何如何在内部工作?在我正在进行的一个项目中,我目前使用标记联合。我想使用其他东西,因为 C++ 中的联合不允许您使用带有构造函数、析构函数或重载赋值运算符的对象。
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.
我查询了 any 和 variant 的大小,并用它们做了一些实验。在我的平台中,variant 取其最长可能类型的大小加上 8 个字节:我认为它只是 8 个字节的类型信息,其余的是存储的值。另一方面, any 只需要 8 个字节。由于我在 64 位平台上,我猜任何只是持有一个指针。
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.
Any 怎么知道它拥有什么类型?Variant 如何通过模板实现其功能?在使用它们之前,我想更多地了解这些类。
回答by Edward Strange
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
如果您阅读 boost::any 文档,它们会提供该想法的来源:http: //www.two-sdg.demon.co.uk/curbralan/papers/ValuedConversions.pdf
It's basic information hiding, an essential C++ skill to have. Learn it!
它是基本的信息隐藏,是必备的 C++ 技能。学习它!
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:
由于这里投票最高的答案完全不正确,而且我怀疑人们实际上会查看源代码以验证这一事实,因此这里是 any like 接口的基本实现,它将用 f() 函数包装任何类型和允许它被称为:
struct f_any
{
f_any() : ptr() {}
~f_any() { delete ptr; }
bool valid() const { return ptr != 0; }
void f() { assert(ptr); ptr->f(); }
struct placeholder
{
virtual ~placeholder() {}
virtual void f() const = 0;
};
template < typename T >
struct impl : placeholder
{
impl(T const& t) : val(t) {}
void f() const { val.f(); }
T val;
};
// ptr can now point to the entire family of
// struct types generated from impl<T>
placeholder * ptr;
template < typename T >
f_any(T const& t) : ptr(new impl<T>(t)) {}
// assignment, etc...
};
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 做同样的基本事情,除了 f() 实际上返回typeinfo const&
并提供其他信息访问 any_cast 函数来工作。
回答by Michael Aaron Safyan
The key difference between boost::any
and boost::variant
is that any
can store any type, while variant
can store only one of a set of enumerated types. The any
type stores a void*
pointer to the object, as well as a typeinfo
object to remember the underlying type and enforce some degree of type safety. In boost::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.
boost::any
和之间的主要区别boost::variant
是any
可以存储任何类型,而variant
只能存储一组枚举类型中的一个。该any
类型存储一个void*
指向对象的指针,以及一个typeinfo
对象来记住底层类型并强制执行某种程度的类型安全。在 中boost::variant
,它计算最大大小的对象,并使用“placement new”在此缓冲区内分配对象。它还存储类型或类型索引。
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.
请注意,如果您安装了 Boost,您应该能够在“any.hpp”和“variant.hpp”中看到源文件。只需在“/usr”、“/usr/local”和“/opt/local”中搜索“include/boost/variant.hpp”和“include/boost/any.hpp”,直到找到已安装的头文件,然后你可以看看。
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 uses any<T>::placeholder*
, with any<T>::holder<T>
as subclasses of any<T>::placeholder
for unifying the type.
编辑
正如在下面的评论中指出的那样,我对 boost::any 的描述有一点不准确。虽然它可以使用void*
(和模板化的销毁回调来正确删除指针)来实现,但实际的实现使用any<T>::placeholder*
,any<T>::holder<T>
作为any<T>::placeholder
统一类型的子类。
回答by Tony Delroy
boost::any
just snapshots the typeinfo
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::any
只是typeinfo
在模板化构造函数运行时进行快照:它有一个指向非模板化基类的指针,该基类提供对 typeinfo 的访问,并且构造函数派生出一个满足该接口的特定于类型的类。实际上可以使用相同的技术来捕获一组类型的其他通用功能(例如流、通用运算符、特定函数),尽管 boost 不提供对此的控制。
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 actual union
s.
boost::variant 在概念上与您之前所做的类似,但通过不使用 aunion
而是采用手动方法在其缓冲区中放置构建/销毁对象(同时明确处理对齐问题),它可以绕过以下限制: C++ 在实际的union
s 中有复杂的类型。